Java'daki bir dosyadan belirli bir satır numarasını kullanarak belirli bir satırı nasıl okuyabilirim?


91

Java'da, bir dosyadan belirli bir satırı okumak için herhangi bir yöntem var mı? Örneğin, 32. satırı veya başka bir satır numarasını okuyun.


5
Çok geç kaldığımı biliyorum, ancak birinin şu soruyu bulması durumunda: Bir dosyanın sadece bir bayt dizisi olduğunu unutmayın. Ve bir satırsonu yalnızca bir karakterdir (Windows'ta iki) ve bir karakter yalnızca bir (veya kodlamaya bağlı olarak daha fazla) bayttır. Ve bir dosyadaki bir baytın konumlarının bir dizini olmadan, bu baytların nerede olduğunu bilmenin tek yolu onu okumak ve aramaktır. (bu, tüm dosyayı belleğe yüklemeniz gerektiği anlamına gelmez).
szgal

Yanıtlar:


72

Dosyadaki satırlar hakkında önceden bilginiz olmadıkça, önceki 31 satırı okumadan 32. satıra doğrudan erişmenin bir yolu yoktur.

Bu, tüm diller ve tüm modern dosya sistemleri için geçerlidir.

O kadar etkili bir şekilde 32'nci satırı bulana kadar basitçe okuyacaksınız.


4
"Önceki bilgiler", dosyadaki kesin çizgi boyutu modeli kadar basit olabilir, böylece belirli bir konuma gidebilirsiniz.
Murali Başkan Yardımcısı

2
@Murali: Elbette. Ayrıca, bayt uzaklığına veya bunların herhangi bir kombinasyonuna göre bir satır numarası indeksi de olabilir.
Joachim Sauer

105

Küçük dosyalar için:

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

Büyük dosyalar için:

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

Bu, java.nio.charset.MalformedInputException döndürür: Atlama değeri 1 olarak kullanıldığında giriş uzunluğu = 1
canadiancreed

Bu, yayınladığım kodla ilgili bir sorun değil, dosyanızın kodlanmasıyla ilgili bir sorun. Bu gönderiye bakın .
aioobe

4
"Bu yöntemin, tek bir işlemde tüm satırları okumanın uygun olduğu basit durumlar için tasarlandığını unutmayın. Büyük dosyalarda okumak için tasarlanmamıştır." - Files.readAllLines () için Javadoc
PragmaticProgrammer

Aşağıdaki kod, android'de API seviyesi 26 gerektirir.
Minimiz

38

Bildiğimden değil, ama yapabileceğiniz şey, BufferedReader'ın readline () işlevini kullanarak hiçbir şey yapmadan ilk 31 satır boyunca döngü yapmaktır.

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
Lütfen burada 31. satır olan 30 numaralı satırı okuduğunuzu unutmayın, çünkü satır numaralarını 0'dan başlatıyoruz. Bu yüzden soruyu tam olarak eşleştirmek için değiştirmenizi öneririm.
kiedysktos

15

Joachim elbette haklıdır ve Chris'in alternatif bir uygulaması (yalnızca dosyanın tamamını yüklediği için küçük dosyalar için) Apache'nin commons-io'yu kullanmak olabilir (ancak muhtemelen yalnızca yeni bir bağımlılık eklemek istemeyebilirsiniz) bu, başka şeyler için de yararlı bulursanız, mantıklı olabilir).

Örneğin:

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
Bu, 32. satıra gitmeden önce tüm dosyayı belleğe yükleyecektir, bu büyük bir dosya için pratik olmayabilir ve 32. satırı bulmaktan okumadan daha yavaş olabilir ...
beny23

Doğru nokta, evet. Bunu, test dosyalarının küçük olduğu test durumlarında, büyük dosyalarda olsa da kabul ettim, iyi bir yaklaşım değil.
Charlie Collins

Büyük bir dosyanız varsa ve X satırının ötesinde bir şeye ihtiyacınız yoksa, FileUtils'in bu kullanım durumunda kötü bir fikir olduğunu yansıtacak şekilde güncellenmiş yanıt yazısı.
Charlie Collins

11

İndekslenmiş dosya okuyucuyu (Apache Lisans 2.0) deneyebilirsiniz . IndexedFileReader sınıfı , anahtarı satır numarası ve değeri okunan satır olan bir SortedMap döndüren readLines (int from, int to) adında bir yönteme sahiptir .

Misal:

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]"));      

Yukarıdaki örnek, aşağıdaki formatta 50 satırdan oluşan bir metin dosyasını okur:

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

Disclamer: Bu kütüphaneyi yazdım


6

Her ne kadar diğer cevaplarda da söylendiği gibi, daha önce ofseti (işaretçiyi) bilmeden tam satıra ulaşmak mümkün değildir. Bunu, her satırın ofset değerlerini depolayacak geçici bir dizin dosyası oluşturarak başardım. Dosya yeterince küçükse, dizinleri (ofset) ayrı bir dosyaya ihtiyaç duymadan bellekte saklayabilirsiniz.

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();

Daha fazla bilgi için java dokümanlarını da ziyaret edin: https://docs.oracle.com/javase/8/docs/api/java/io/RandomAccessFile.html#mode

Karmaşıklık : Tüm dosyayı bir kez okuduğu için bu O (n) 'dir. Lütfen bellek gereksinimlerine dikkat edin. Bellekte olmayacak kadar büyükse, yukarıda gösterildiği gibi ArrayList yerine ofsetleri depolayan geçici bir dosya oluşturun.

Not : '32' satırında istediğiniz tek şey varsa, diğer sınıflarda '32' kez de mevcut olan readLine () 'i çağırmanız yeterlidir. Yukarıdaki yaklaşım, belirli bir satırı (tabii ki satır numarasına göre) birden çok kez almak istiyorsanız kullanışlıdır.

Teşekkürler !


Yukarıdaki kodun çalışması için düzenleme yapılması gereken bir şey var. Ve birinin karakter
setine

5

Diğer yol.

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
Zarif, beğendim.
Florescu Cătălin

4

Hayır, bu dosya biçiminde satır uzunlukları önceden belirlenmedikçe (örneğin, sabit uzunluktaki tüm satırlar), bunları saymak için satır satır yinelemeniz gerekir.


2

Bir metin dosyasından bahsediyorsanız, bundan önceki tüm satırları okumadan bunu yapmanın gerçekten bir yolu yoktur - Sonuçta, satırlar bir satırsonu varlığına göre belirlenir, bu nedenle okunması gerekir.

Readline'ı destekleyen bir akım kullanın ve sadece ilk X-1 satırlarını okuyun ve sonuçları boşaltın, ardından bir sonrakini işleyin.


2

Java 8'de,

Küçük dosyalar için:

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

Büyük dosyalar için:

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

Java 7'de

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

Kaynak: Dosyadan n'inci satır okunuyor


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

Benim için çalışıyor: Basit bir metin dosyasını okuma cevabını birleştirdim

Ama bir String döndürmek yerine, LinkedList of Strings'i döndürüyorum. Sonra istediğim hattı seçebilirim.

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;
}

Daha sonra şunları yapabilirsiniz: linkedlist.get (31)
Tachenko

1

Bu kodu kullanın:

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 yerine LineNumberReader'ı kullanabilirsiniz. API'den geçin. SetLineNumber ve getLineNumber yöntemlerini bulabilirsiniz.


yardımcı olmuyor - yine de daha önce tüm satırları okumanız gerekiyor ... hile yapıp ilk satırı 32 <g> olarak ayarlamanız dışında
kleopatra

0

Ayrıca BufferedReader'ın alt sınıfı olan LineNumberReader'a da göz atabilirsiniz. Readline yönteminin yanı sıra, satır numarasına erişmek için ayarlayıcı / alıcı yöntemleri de vardır. Dosyadan veri okurken okunan satır sayısını takip etmek için çok kullanışlıdır.


0

satırları baştan atlamak için skip () işlevini kullanabilirsiniz.

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);

}

0

KOLAY YOL - Satır numarasını kullanarak bir satırı okumak. Diyelim ki Satır numarası 1'den sıfıra kadar başlıyor.

public class TextFileAssignmentOct {
    
    private void readData(int rowNum, BufferedReader br) throws IOException {
        int n=1;                                    //Line number starts from 1
        String row;
        while((row=br.readLine()) != null)  {       // Reads every line
            if (n == rowNum) {                      // When Line number matches with which you want to read
                System.out.println(row);
            }
            n++;                                    //This increments Line number
        }
    }

    public static void main(String[] args) throws IOException {
        File f = new File("../JavaPractice/FileRead.txt");
        FileReader fr = new FileReader(f);
        BufferedReader br = new BufferedReader(fr);
        
        TextFileAssignmentOct txf = new TextFileAssignmentOct();
        txf.readData(4, br);    //Read a Specific Line using Line number and Passing buffered reader
    }
}

-7

Hepsi yanılıyor, bunu yaklaşık 10 saniye içinde yazdım. Bununla istediğim satırı döndürmek için ana yöntemde object.getQuestion'u ("keten numarası") çağırmayı başardım.

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; }}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.