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.