2008-08-06 24 views
81

Tôi có một ứng dụng ghi thông tin vào tập tin. Thông tin này được sử dụng sau khi thực hiện để xác định pass/failure/correctness của ứng dụng. Tôi muốn có thể đọc các tập tin như nó đang được viết để tôi có thể làm các kiểm tra pass/fail/correctness trong thời gian thực.Làm cách nào để sử dụng Java để đọc từ một tệp đang được tích cực ghi vào?

Tôi cho rằng có thể thực hiện điều này, nhưng có liên quan gì khi sử dụng Java? Nếu đọc bắt kịp với văn bản, nó sẽ chỉ chờ đợi cho viết nhiều hơn cho đến khi tập tin được đóng lại, hoặc sẽ đọc ném một ngoại lệ vào thời điểm này? Nếu sau này, tôi phải làm gì?

Trực giác của tôi hiện đang đẩy tôi tới BufferedStreams. Đây có phải là con đường để đi?

+1

hey, như tôi đang phải đối mặt với một kịch bản tương tự như tôi đã từ ngữ nếu bạn đã tìm thấy một giải pháp tốt hơn so với cái được chấp nhận? –

+0

Tôi biết đây là một câu hỏi cũ, nhưng vì lợi ích của độc giả trong tương lai, bạn có thể mở rộng thêm về trường hợp sử dụng của mình thêm một chút không? Nếu không có thêm thông tin, người ta tự hỏi nếu bạn có thể giải quyết vấn đề sai. – user359996

+2

Sử dụng cơ sở dữ liệu. Những 'đọc một tập tin trong khi nó được viết' kịch bản kết thúc trong nước mắt. – EJP

Trả lời

34

Không thể lấy ví dụ để làm việc sử dụng FileChannel.read(ByteBuffer) bởi vì nó không phải là một ngăn chặn đọc. tuy nhiên đã nhận được mã dưới đây để làm việc:

boolean running = true; 
BufferedInputStream reader = new BufferedInputStream(new FileInputStream("out.txt")); 

public void run() { 
    while(running) { 
     if(reader.available() > 0) { 
      System.out.print((char)reader.read()); 
     } 
     else { 
      try { 
       sleep(500); 
      } 
      catch(InterruptedException ex) { 
       running = false; 
      } 
     } 
    } 
} 

Tất nhiên điều tương tự sẽ làm việc như một bộ đếm thời gian thay vì một chủ đề, nhưng tôi rời khỏi đó đến các lập trình viên. Tôi vẫn đang tìm kiếm một cách tốt hơn, nhưng điều này làm việc cho tôi bây giờ.

Ồ, và tôi sẽ báo trước điều này với: Tôi đang sử dụng 1.4.2. Có, tôi biết tôi vẫn còn trong thời kỳ đồ đá.

+1

Cảm ơn bạn đã thêm điều này ... điều mà tôi không bao giờ có xung quanh để làm. Tôi nghĩ rằng câu trả lời của Blade về việc khóa tập tin cũng là một câu trả lời hay. Tuy nhiên, nó đòi hỏi Java 6 (tôi nghĩ). –

+0

@AnthonyCramp tại sao bạn không cho tiền thưởng? :) –

+0

@JosephGordon - Bạn sẽ phải chuyển sang tuổi Drone một trong những ngày này ;-) – TungstenX

1

Không phải Java, nhưng bạn có thể gặp phải sự cố mà bạn đã viết gì đó vào một tệp nhưng chưa thực sự được viết - có thể trong bộ đệm ở đâu đó và đọc từ cùng một tệp không thực sự cung cấp cho bạn thông tin mới.

ngắn phiên bản - sử dụng flush() hoặc bất cứ hệ thống gọi có liên quan là để đảm bảo rằng dữ liệu của bạn là thực sự ghi vào tập tin.

Lưu ý tôi không nói về bộ nhớ cache đĩa cấp hệ điều hành - nếu dữ liệu của bạn được vào đây, nó sẽ xuất hiện trong một read() sau thời điểm này. Nó có thể là ngôn ngữ chính nó lưu trữ viết, chờ đợi cho đến khi một bộ đệm đầy lên hoặc tập tin được đỏ bừng/đóng cửa.

0

Tôi chưa bao giờ thử nó, nhưng bạn nên viết một trường hợp thử nghiệm để xem nếu đọc từ một dòng suối sau khi bạn đã nhấn cuối cùng sẽ làm việc, bất kể nếu có nhiều dữ liệu được ghi vào tập tin.

Có lý do nào khiến bạn không thể sử dụng luồng đầu vào/đầu ra đường ống không? Dữ liệu được viết và đọc từ cùng một ứng dụng (nếu có, bạn có dữ liệu, tại sao bạn cần đọc từ tệp)?

Nếu không, có lẽ đọc đến cuối tập tin, sau đó theo dõi các thay đổi và tìm cách nơi bạn rời đi và tiếp tục ... mặc dù xem ra cho điều kiện chủng tộc.

3

Câu trả lời có vẻ là "không" ... và "có". Dường như không có cách nào thực sự để biết liệu một tập tin có được mở để viết bởi một ứng dụng khác hay không. Vì vậy, việc đọc từ một tệp như vậy sẽ chỉ diễn ra cho đến khi nội dung cạn kiệt. Tôi nghe theo lời khuyên của Mike và viết một số mã kiểm tra:

Writer.java viết một chuỗi vào tập tin và sau đó chờ đợi cho người dùng để nhấn enter trước khi viết một dòng khác để nộp. Ý tưởng được rằng nó có thể được bắt đầu lên, sau đó một người đọc có thể được bắt đầu để xem làm thế nào nó đối phó với các tập tin "một phần". Người đọc tôi đã viết nằm trong Reader.java.

Writer.java

public class Writer extends Object 
{ 
    Writer() { 

    } 

    public static String[] strings = 
     { 
      "Hello World", 
      "Goodbye World" 
     }; 

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

     java.io.PrintWriter pw = 
      new java.io.PrintWriter(new java.io.FileOutputStream("out.txt"), true); 

     for(String s : strings) { 
      pw.println(s); 
      System.in.read(); 
     } 

     pw.close(); 
    } 
} 

Reader.java

public class Reader extends Object 
{ 
    Reader() { 

    } 

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

     java.io.FileInputStream in = new java.io.FileInputStream("out.txt"); 

     java.nio.channels.FileChannel fc = in.getChannel(); 
     java.nio.ByteBuffer bb = java.nio.ByteBuffer.allocate(10); 

     while(fc.read(bb) >= 0) { 
      bb.flip(); 
      while(bb.hasRemaining()) { 
       System.out.println((char)bb.get()); 
      } 
      bb.clear(); 
     } 

     System.exit(0); 
    } 
} 

Không đảm bảo rằng mã này là thực hành tốt nhất.

Tùy chọn này được Mike đề xuất định kỳ kiểm tra xem có dữ liệu mới được đọc từ tệp hay không. Điều này sau đó yêu cầu người dùng can thiệp để đóng trình đọc tệp khi xác định rằng việc đọc hoàn tất. Hoặc, người đọc cần phải được thực hiện nhận thức được nội dung của tập tin và có thể xác định và kết thúc điều kiện ghi. Nếu nội dung là XML, phần cuối của tài liệu có thể được sử dụng để báo hiệu điều này.

5

Bạn cũng có thể xem kênh java để khóa một phần của tệp.

http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html

Chức năng này của FileChannel có thể là một sự khởi đầu

lock(long position, long size, boolean shared) 

Một gọi của phương pháp này sẽ chặn cho đến khi khu vực này có thể được khóa

16

Xem xét sử dụng Tailer từ Apache Commons IO. Nó xử lý hầu hết các trường hợp cạnh.

1

Có một mã nguồn mở Java Graphic Tail thực hiện việc này.

https://stackoverflow.com/a/559146/1255493

public void run() { 
    try { 
     while (_running) { 
      Thread.sleep(_updateInterval); 
      long len = _file.length(); 
      if (len < _filePointer) { 
       // Log must have been jibbled or deleted. 
       this.appendMessage("Log file was reset. Restarting logging from start of file."); 
       _filePointer = len; 
      } 
      else if (len > _filePointer) { 
       // File must have had something added to it! 
       RandomAccessFile raf = new RandomAccessFile(_file, "r"); 
       raf.seek(_filePointer); 
       String line = null; 
       while ((line = raf.readLine()) != null) { 
        this.appendLine(line); 
       } 
       _filePointer = raf.getFilePointer(); 
       raf.close(); 
      } 
     } 
    } 
    catch (Exception e) { 
     this.appendMessage("Fatal error reading log file, log tailing has stopped."); 
    } 
    // dispose(); 
} 
5

Tôi hoàn toàn đồng ý với Joshua's response, Tailer là thích hợp cho công việc trong tình huống này. Dưới đây là một ví dụ:

Nó viết một dòng mỗi 150 ms trong một tập tin, trong khi đọc rất giống tập tin này mỗi 2500 ms

public class TailerTest 
{ 
    public static void main(String[] args) 
    { 
     File f = new File("/tmp/test.txt"); 
     MyListener listener = new MyListener(); 
     Tailer.create(f, listener, 2500); 

     try 
     { 
      FileOutputStream fos = new FileOutputStream(f); 
      int i = 0; 
      while (i < 200) 
      { 
       fos.write(("test" + ++i + "\n").getBytes()); 
       Thread.sleep(150); 
      } 
      fos.close(); 
     } 
     catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 
    } 

    private static class MyListener extends TailerListenerAdapter 
    { 
     @Override 
     public void handle(String line) 
     { 
      System.out.println(line); 
     } 
    } 
} 
+0

Liên kết đến Tailer của bạn bị hỏng. –

+1

@StealthRabbi Điều tốt nhất để làm sau đó là tìm kiếm liên kết chính xác và chỉnh sửa câu trả lời với nó. – igracia

4

Nếu bạn muốn đọc một tập tin trong khi nó đang được viết và chỉ đọc nội dung mới sau đó sẽ giúp bạn đạt được như vậy.

Để chạy chương trình này, bạn sẽ khởi chạy chương trình từ cửa sổ lệnh/cửa sổ dòng lệnh và chuyển tên tệp để đọc. Nó sẽ đọc các tập tin, trừ khi bạn giết chương trình.

java FileReader c: \ myfile.txt

Khi bạn gõ một dòng văn bản lưu nó từ notepad và bạn sẽ thấy những văn bản in trong giao diện điều khiển.

public class FileReader { 

    public static void main(String args[]) throws Exception { 
     if(args.length>0){ 
      File file = new File(args[0]); 
      System.out.println(file.getAbsolutePath()); 
      if(file.exists() && file.canRead()){ 
       long fileLength = file.length(); 
       readFile(file,0L); 
       while(true){ 

        if(fileLength<file.length()){ 
         readFile(file,fileLength); 
         fileLength=file.length(); 
        } 
       } 
      } 
     }else{ 
      System.out.println("no file to read"); 
     } 
    } 

    public static void readFile(File file,Long fileLength) throws IOException { 
     String line = null; 

     BufferedReader in = new BufferedReader(new java.io.FileReader(file)); 
     in.skip(fileLength); 
     while((line = in.readLine()) != null) 
     { 
      System.out.println(line); 
     } 
     in.close(); 
    } 
} 
+2

Không có khả năng rằng, giữa thời gian tệp được đọc và thời gian thực hiện độ dài tệp, quy trình bên ngoài có thể thêm nhiều dữ liệu hơn vào tệp. Nếu vậy, điều này sẽ dẫn đến quá trình đọc thiếu dữ liệu được ghi vào tệp. – JohnC

+0

Mã này tiêu thụ rất nhiều CPU bởi vì vòng lặp không có một cuộc gọi thread.sleep trong đó. Nếu không thêm một số lượng nhỏ của sự chậm trễ mã này có xu hướng giữ cho CPU rất bận rộn. – ChaitanyaBhatt

0

Bạn không thể đọc tệp được mở từ quá trình khác bằng FileInputStream, FileReader hoặc RandomAccessFile.

Nhưng sử dụng FileChannel trực tiếp sẽ làm việc:

private static byte[] readSharedFile(File file) throws IOException { 
    byte buffer[] = new byte[(int) file.length()]; 
    final FileChannel fc = FileChannel.open(file.toPath(), EnumSet.of(StandardOpenOption.READ)); 
    final ByteBuffer dst = ByteBuffer.wrap(buffer); 
    fc.read(dst); 
    fc.close(); 
    return buffer; 
} 
Các vấn đề liên quan