如何使用Java中的文件中的特定行号读取特定行?


90

在Java中,是否有任何方法可以从文件中读取特定行?例如,读取第32行或任何其他行号。


5
我知道我来晚了,但是如果有人发现了这个问题:请注意,文件只是一个字节序列。一个换行符只是一个字符(在Windows上是两个),而一个字符只是一个(或多个,取决于编码)字节。而且,在没有索引文件中字节位置的情况下,知道这些字节在哪里的唯一方法是读取并查找它。(但这并不意味着您必须将整个文件加载到内存中)。
szgal 2015年

Answers:


71

除非您以前对文件中的行有一定的了解,否则没有阅读前31行就无法直接访问第32行。

所有语言和所有现代文件系统都是如此。

如此有效地,您只需阅读第32行,直到找到第32行。


4
“以前的知识”可以很简单,就像文件中精确的行大小样式一样,因此您可以查找到某个位置。
Murali副总裁

2
@Murali:当然。它也可以是行号到字节偏移的索引或其任何组合。
约阿希姆·绍尔

103

对于小文件:

String line32 = Files.readAllLines(Paths.get("file.txt")).get(32)

对于大文件:

try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
    line32 = lines.skip(31).findFirst().get();
}

这将返回java.nio.charset.MalformedInputException:输入长度= 1(使用跳过值为1时)
canadiancreed

这不是我发布的代码的问题,而是文件编码的问题。看到这篇文章
aioobe

3
“请注意,此方法仅适用于简单的情况,在这种情况下,一次操作即可轻松读取所有行。不适用于读取大文件。” -Files.readAllLines()的Javadoc
PragmaticProgrammer

以下代码要求Android中的API级别为26。如果我们的最小值小于该水平,那么它将不起作用
Ali Azaz Alam

38

我不知道,但是您可以做的是使用BufferedReader的readline()函数遍历前31行,什么也不做

FileInputStream fs= new FileInputStream("someFile.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fs));
for(int i = 0; i < 31; ++i)
  br.readLine();
String lineIWant = br.readLine();

1
请注意,这里您读取的是第30行,即第31行,因为我们从0开始。所以我建议更改它以使其与问题完全匹配。
kiedysktos 2015年

15

当然,Joachim是正确的,而Chris'的另一种实现(仅适用于小文件,因为它加载了整个文件)可能是使用来自Apache的commons-io(尽管可以说,您可能不想仅为此引入新的依赖项)这样,如果您发现它对其他内容也很有用,则可能是有道理的)。

例如:

String line32 = (String) FileUtils.readLines(file).get(31);

http://commons.apache.org/io/api-release/org/apache/commons/io/FileUtils.html#readLines(java.io.File,java.lang.String


2
尽管那样会在进入第32行之前将整个文件加载到内存中,这对于大文件而言可能不切实际,并且比读取util找到第32行要慢...
beny23 '02

公平点,是的。我曾在测试用例中使用过这种方法,尽管测试文件很小,但在大文件上却认为这不是一个好方法。
查理·柯林斯

更新后的答案,以反映文件实用程序是在这种使用情况下是一个坏主意,如果你有一个大的文件,不需要任何超越线X
查理·柯林斯

11

您可以尝试使用索引文件阅读器(Apache许可证2.0)。IndexedFileReader类具有一个名为readLines(int from,int to)的方法,该方法返回SortedMap,其键是行号,值是已读取的行。

例:

File file = new File("src/test/resources/file.txt");
reader = new IndexedFileReader(file);

lines = reader.readLines(6, 10);
assertNotNull("Null result.", lines);
assertEquals("Incorrect length.", 5, lines.size());
assertTrue("Incorrect value.", lines.get(6).startsWith("[6]"));
assertTrue("Incorrect value.", lines.get(7).startsWith("[7]"));
assertTrue("Incorrect value.", lines.get(8).startsWith("[8]"));
assertTrue("Incorrect value.", lines.get(9).startsWith("[9]"));
assertTrue("Incorrect value.", lines.get(10).startsWith("[10]"));      

上面的示例以以下格式读取由50行组成的文本文件:

[1] The quick brown fox jumped over the lazy dog ODD
[2] The quick brown fox jumped over the lazy dog EVEN

Disclamer:我写了这个库


6

尽管如其他答案中所述,但在不知道偏移量(指针)的情况下不可能到达确切的行。因此,我通过创建一个临时索引文件来实现此目的,该文件将存储每行的偏移值。如果文件足够小,则只需将索引(offset)存储在内存中,而无需单独的文件。

The offsets can be calculated by using the RandomAccessFile

    RandomAccessFile raf = new RandomAccessFile("myFile.txt","r"); 
    //above 'r' means open in read only mode
    ArrayList<Integer> arrayList = new ArrayList<Integer>();
    String cur_line = "";
    while((cur_line=raf.readLine())!=null)
    {
    arrayList.add(raf.getFilePointer());
    }
    //Print the 32 line
    //Seeks the file to the particular location from where our '32' line starts
    raf.seek(raf.seek(arrayList.get(31));
    System.out.println(raf.readLine());
    raf.close();

另请访问Java文档以获取更多信息:https : //docs.oracle.com/javase/8/docs/api/java/io/RandomAccessFile.html#mode

复杂度:这是O(n),因为它一次读取整个文件。请注意内存要求。如果太大而无法存储在内存中,请制作一个临时文件来存储偏移量而不是ArrayList,如上所示。

注意:如果只想在“ 32”行中输入内容,则只需调用readLine()即可,其他类也可以使用“ 32”次。如果您想多次获得一条特定的线(基于路线数),上述方法很有用。

谢谢 !


需要进行一些编辑才能使上面的代码起作用。如果有人需要有关字符集的信息,那么您真的应该阅读以下内容:stackoverflow.com/a/372​​75357/3198960
rufushuang

5

其他方式。

try (BufferedReader reader = Files.newBufferedReader(
        Paths.get("file.txt"), StandardCharsets.UTF_8)) {
    List<String> line = reader.lines()
                              .skip(31)
                              .limit(1)
                              .collect(Collectors.toList());

    line.stream().forEach(System.out::println);
}

1
优雅,我喜欢。
FlorescuCătălin17年

4

不可以,除非以该文件格式确定行长(例如,所有具有固定长度的行),否则您必须逐行进行迭代以对其进行计数。


2

如果您正在谈论文本文件,那么不读取它前面的所有行实际上是没有办法的-毕竟,行是由换行符的存在决定的,因此必须对其进行读取。

使用支持readline的流,只读取前X-1行并转储结果,然后处理下一行。


2

在Java 8中,

对于小文件:

String line = Files.readAllLines(Paths.get("file.txt")).get(n);

对于大文件:

String line;
try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
    line = lines.skip(n).findFirst().get();
}

在Java 7中

String line;
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
    for (int i = 0; i < n; i++)
        br.readLine();
    line = br.readLine();
}

来源:从文件中读取第n行


1
public String readLine(int line){
        FileReader tempFileReader = null;
        BufferedReader tempBufferedReader = null;
        try { tempFileReader = new FileReader(textFile); 
        tempBufferedReader = new BufferedReader(tempFileReader);
        } catch (Exception e) { }
        String returnStr = "ERROR";
        for(int i = 0; i < line - 1; i++){
            try { tempBufferedReader.readLine(); } catch (Exception e) { }
        }
        try { returnStr = tempBufferedReader.readLine(); }  catch (Exception e) { }

        return returnStr;
    }

1

它对我有用:我综合了阅读简单文本文件的答案

但是,不是返回字符串,而是返回字符串的LinkedList。然后,我可以选择所需的行。

public static LinkedList<String> readFromAssets(Context context, String filename) throws IOException {
    BufferedReader reader = new BufferedReader(new InputStreamReader(context.getAssets().open(filename)));
    LinkedList<String>linkedList = new LinkedList<>();
    // do reading, usually loop until end of file reading
    StringBuilder sb = new StringBuilder();
    String mLine = reader.readLine();
    while (mLine != null) {
        linkedList.add(mLine);
        sb.append(mLine); // process line
        mLine = reader.readLine();


    }
    reader.close();
    return linkedList;
}

然后,你可以这样做:linkedlist.get(31)
Tachenko

1

使用此代码:

import java.nio.file.Files;

import java.nio.file.Paths;

public class FileWork 
{

    public static void main(String[] args) throws IOException {

        String line = Files.readAllLines(Paths.get("D:/abc.txt")).get(1);

        System.out.println(line);  
    }

}

0

您可以使用LineNumberReader而不是BufferedReader。通过api。您可以找到setLineNumber和getLineNumber方法。


无济于事-您仍然必须先阅读所有内容...除非作弊,然后将第一行设置为32 <g>
kleopatra 2012年

0

您还可以查看BufferedReader的子类LineNumberReader。除了readline方法外,它还具有setter / getter方法来访问行号。在从文件读取数据时,跟踪读取的行数非常有用。


0

您可以使用skip()函数从头开始跳过行。

public static void readFile(String filePath, long lineNum) {
    List<String> list = new ArrayList<>();
    long totalLines, startLine = 0;

    try (Stream<String> lines = Files.lines(Paths.get(filePath))) {
        totalLines = Files.lines(Paths.get(filePath)).count();
        startLine = totalLines - lineNum;
        // Stream<String> line32 = lines.skip(((startLine)+1));

        list = lines.skip(startLine).collect(Collectors.toList());
        // lines.forEach(list::add);
    } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

    list.forEach(System.out::println);

}

-7

他们都是错误的,我只是在10秒钟左右就写完了。有了这个,我设法在main方法中调用object.getQuestion(“ linenumber”)以返回我想要的任何行。

public class Questions {

File file = new File("Question2Files/triviagame1.txt");

public Questions() {

}

public String getQuestion(int numLine) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(file));
    String line = "";
    for(int i = 0; i < numLine; i++) {
        line = br.readLine();
    }
    return line; }}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.