현재 기록중인 파일에서 Java를 사용하여 읽으려면 어떻게해야합니까?
파일에 정보를 쓰는 응용 프로그램이 있습니다. 이 정보는 애플리케이션의 합격 / 불합격 / 정확성을 결정하기 위해 실행 후 사용됩니다. 실시간으로 이러한 합격 / 불합격 / 정확성 검사를 수행 할 수 있도록 작성중인 파일을 읽을 수 있기를 바랍니다.
나는 이것을 할 수 있다고 가정하지만 Java를 사용할 때 어떤 문제가 있습니까? 읽기가 쓰기를 따라 잡으면 파일이 닫힐 때까지 더 많은 쓰기를 기다릴까요, 아니면이 시점에서 읽기가 예외를 던질까요? 후자의 경우 어떻게해야합니까?
내 직감은 현재 나를 BufferedStreams로 밀고 있습니다. 이게 갈 길 이니?
FileChannel.read(ByteBuffer)
차단 읽기가 아니기 때문에 예제를 사용하여 작동시킬 수 없습니다 . 그러나 작동하려면 아래 코드를 얻었습니다.
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;
}
}
}
}
물론 똑같은 것이 스레드 대신 타이머로 작동하지만 프로그래머에게 맡기십시오. 나는 여전히 더 나은 방법을 찾고 있지만 지금은 이것이 나를 위해 작동합니다.
아, 그리고 이것에 대해주의 할 것입니다 : 1.4.2를 사용하고 있습니다. 예, 아직 석기 시대에 있다는 것을 압니다.
작성하는 동안 파일을 읽고 새 내용 만 읽으려면 다음을 수행하면 동일한 결과를 얻을 수 있습니다.
이 프로그램을 실행하려면 명령 프롬프트 / 터미널 창에서 실행하고 읽을 파일 이름을 전달합니다. 프로그램을 종료하지 않으면 파일을 읽습니다.
자바 FileReader c : \ myfile.txt
텍스트 줄을 입력 할 때 메모장에서 저장하면 콘솔에 인쇄 된 텍스트가 표시됩니다.
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();
}
}
파일의 일부를 잠그기 위해 Java 채널을 살펴볼 수도 있습니다.
http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html
이 기능은 FileChannel
시작이 될 수 있습니다.
lock(long position, long size, boolean shared)
이 메서드의 호출은 영역을 잠글 수있을 때까지 차단됩니다.
나는 Joshua의 반응에 전적으로 동의합니다 . Tailer 는이 상황에서 일에 적합합니다. 다음은 예입니다.
파일에 150ms마다 한 줄을 쓰고 2500ms마다 동일한 파일을 읽습니다.
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);
}
}
}
대답은 "아니오"... 그리고 "예"인 것 같습니다. 다른 응용 프로그램에서 쓰기 위해 파일이 열려 있는지 알 수있는 실제 방법이없는 것 같습니다. 따라서 이러한 파일에서 읽는 것은 내용이 모두 소진 될 때까지 진행됩니다. 나는 Mike의 조언을 듣고 몇 가지 테스트 코드를 작성했습니다.
Writer.java writes a string to file and then waits for the user to hit enter before writing another line to file. The idea being that it could be started up, then a reader can be started to see how it copes with the "partial" file. The reader I wrote is in 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);
}
}
No guarantees that this code is best practice.
This leaves the option suggested by Mike of periodically checking if there is new data to be read from the file. This then requires user intervention to close the file reader when it is determined that the reading is completed. Or, the reader needs to be made aware the content of the file and be able to determine and end of write condition. If the content were XML, the end of document could be used to signal this.
Not Java per-se, but you may run into issues where you have written something to a file, but it hasn't been actually written yet - it might be in a cache somewhere, and reading from the same file may not actually give you the new information.
Short version - use flush() or whatever the relevant system call is to ensure that your data is actually written to the file.
Note I am not talking about the OS level disk cache - if your data gets into here, it should appear in a read() after this point. It may be that the language itself caches writes, waiting until a buffer fills up or file is flushed/closed.
There are a Open Source Java Graphic Tail that does this.
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();
}
You can't read a file which is opened from another process using FileInputStream, FileReader or RandomAccessFile.
But using FileChannel directly will work:
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;
}
I've never tried it, but you should write a test case to see if reading from a stream after you have hit the end will work, regardless of if there is more data written to the file.
Is there a reason you can't use a piped input/output stream? Is the data being written and read from the same application (if so, you have the data, why do you need to read from the file)?
Otherwise, maybe read till end of file, then monitor for changes and seek to where you left off and continue... though watch out for race conditions.
'Programming' 카테고리의 다른 글
Xcode 7.3 자동 완성은 너무 실망 스럽습니다. (0) | 2020.08.25 |
---|---|
교차 도메인 인증을 위해 JWT를 사용하는 싱글 사인온 플로우 (0) | 2020.08.25 |
대형 개체 힙 조각화 (0) | 2020.08.25 |
R 스크립트 줄 번호 오류? (0) | 2020.08.25 |
Swift 변수는 원자 적입니까? (0) | 2020.08.25 |