Java의 파일에서 특정 줄 번호를 사용하여 특정 줄을 읽는 방법은 무엇입니까?


90

Java에서 파일에서 특정 행을 읽는 방법이 있습니까? 예를 들어, 32 행 또는 다른 행 번호를 읽으십시오.


5
나는 내가 매우 늦었다는 것을 알고 있지만 누군가이 질문을 발견 한 경우 : 파일은 단지 일련의 바이트 일뿐입니다. 그리고 개행 문자는 문자 (Windows에서는 2 개)이고 문자는 인코딩에 따라 1 바이트 (또는 그 이상)입니다. 그리고 파일에서 바이트의 위치에 대한 인덱스가 없으면 해당 바이트가 어디에 있는지 알 수있는 유일한 방법은 그것을 읽고 찾는 것입니다. (그래도 전체 파일을 메모리에로드해야한다는 의미는 아닙니다).
— szgal

답변:


71

파일의 줄에 대한 사전 지식이없는 한 이전 31 줄을 읽지 않고 32 번째 줄에 직접 액세스 할 수있는 방법은 없습니다.

이는 모든 언어와 모든 최신 파일 시스템에 해당됩니다.

그래서 효과적으로 당신은 32 번째 줄을 찾을 때까지 단순히 줄을 읽을 것입니다.


4
"이전 지식"은 파일의 정확한 라인 크기 패턴만큼 간단 할 수 있으므로 특정 위치를 찾을 수 있습니다.
— Murali VP

2
@Murali : 물론입니다. 또한 바이트 오프셋에 대한 행 번호의 인덱스 또는 이들의 조합 일 수 있습니다.
— Joachim Sauer

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이 필요합니다. 우리의 분은이 수준은 다음 미만이면 그렇지 일을
— 알리 Azaz 알람

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
여기서는 줄 번호가 0부터 시작하기 때문에 31 번째 줄인 30 번 줄을 읽었습니다. 따라서 질문과 정확하게 일치하도록 변경하는 것이 좋습니다.
— kiedysktos

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 번째 줄로 이동하기 전에 전체 파일을 메모리에로드하지만 대용량 파일에서는 실용적이지 않을 수 있으며 32 번째 줄을 찾는 util을 읽는 것보다 느릴 수 있습니다 ...
— beny23

그렇습니다. 나는 테스트 파일이 작은 테스트 케이스에서 큰 파일에 동의했지만 좋은 접근 방식이 아닙니다.
— Charlie Collins

큰 파일이 있고 X 행 이상이 필요하지 않은 경우 FileUtils가이 유스 케이스에서 나쁜 생각임을 반영하기 위해 업데이트 된 답변 게시물.
— Charlie Collins

11

인덱싱 된 파일 판독기 (Apache License 2.0)를 사용해 볼 수 있습니다 . IndexedFileReader 클래스에는 키가 줄 번호이고 값이 읽은 줄인 SortedMap을 반환하는 readLines (int from, int to) 라는 메서드 가 있습니다.

예:

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

다른 답변에서 말했듯이 이전에 오프셋 (pointer)을 알지 못하면 정확한 줄을 얻을 수 없습니다. 그래서 저는 모든 라인의 오프셋 값을 저장하는 임시 인덱스 파일을 생성하여이를 달성했습니다. 파일이 충분히 작 으면 별도의 파일 없이도 인덱스 (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'줄에서 원하는 모든 것을 원한다면 다른 클래스를 통해 '32'번 사용할 수있는 readLine ()을 호출하면됩니다. 위의 접근 방식은 특정 라인 (물론 라인 번호 기준)을 여러 번 가져 오려는 경우 유용합니다.

감사 !


위의 코드를 작동시키기 위해 편집이 필요한 것이 있습니다. : 사람이 필요 캐릭터 세트가 우려 경우에, u는 정말이 읽어야 stackoverflow.com/a/37275357/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
우아하고 좋아요.
— Florescu CATALIN

4

아니요, 해당 파일 형식에서 줄 길이가 미리 결정되지 않은 경우 (예 : 고정 길이의 모든 줄) 개수를 계산하려면 한 줄씩 반복해야합니다.


2

텍스트 파일에 대해 이야기하고 있다면 그 앞에 오는 모든 줄을 읽지 않고는이 작업을 수행 할 방법이 없습니다. 결국 줄은 개행의 존재에 의해 결정되므로 읽어야합니다.

readline을 지원하는 스트림을 사용하고 첫 번째 X-1 행을 읽고 결과를 덤프 한 후 다음 행을 처리하십시오.


2

자바 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 of Strings를 반환합니다. 그런 다음 원하는 라인을 선택할 수 있습니다.

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 2016

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

BufferedReader 대신 LineNumberReader를 사용할 수 있습니다. API를 살펴보십시오. setLineNumber 및 getLineNumber 메소드를 찾을 수 있습니다.


하지의 도움을 않습니다 - 당신이 속임수 32 <g>에 첫 번째 라인을 설정하기 전에 ...을 제외하고 당신은 여전히 모든 라인을 읽을 필요
— 클레오 파트라

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 초 만에 썼습니다. 이것으로 메인 메소드에서 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; }}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.