How to loop over the lines of a file?

I have a file like:

8
7
6
5
4
3
2
1

I can read it using:


#!/usr/bin/gjs

'use strict';

const Gio = imports.gi.Gio;

const [ok, contents, etag] = file.load_contents(null);
const decoder = new TextDecoder('utf-8');
const contentsString = decoder.decode(contents);

print(contentsString);

Not understanding how to have output like:

line 1 has content 8
line 2 has content 7
...
line 8 has content 1

I’m not sure I see the difference with your other post.

Anyway: here you’re loading the whole contents of the file, so you’ll have to split this by lines manually (deciding what a line is might or might not be tricky, it’s usually either delimited by \n (UNIX-style), \r\n (Windows-style) or historically \r (old MacOS-style): const lines = contentsString.split('\n');. And then iterate over this:

for (const line_no in lines) {
  // beware line_no is a string! no idea why
  print('line ' + line_no + ' has content ' + lines[line_no]);
}

However, a possibly better alternative is going back to your read_line_utf8() (it uses less memory not having to load everything at once, and you don’t have to worry about what a line is yourself):

let stream = new Gio.DataInputStream({
  base_stream: file.read(null),
  close_base_stream: true
});

// just to get line numbers, could otherwise be while(true)
for (let line_no = 1; true; line_no += 1) {
  // read the line and discard the line length (see @andyholmes' answer)
  const [line] = stream.read_line_utf8(null);
  if (line === null) // if there's no more lines, stop
    break;
  print('line ' + line_no + ' has content ' + line);
  // assuming you're continuing on the other question, treat `line` as your path
}

HTH

2 Likes

Thank you very much.

In JavaScript you’ll (almost) always want to use for..of, which is definitely a gotcha compared to other languages:

const lines = [
    'line 1',
    'line 2',
];

// iterating the *key names*
for (const lineKey in lines)
    console.log(`Line Number: ${lineKey}`);

// iterating the value
for (const line of lines)
    console.log(`Line: ${line}`);

P.S. Another gotcha is var, which performs variable hoisting you almost never want. Use let for re-assignable variables, or const otherwise.

1 Like

Thanks! As you might have noticed I’m not very good at JS :confused: – but I learned something :slight_smile:
I slightly updated my answer not to use var then, but will leave the rest to the discretion of the reader depending on his/her needs.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.