Как использовать Java для чтения из файла, в который активно производится запись?

У меня есть приложение, которое записывает информацию в файл. Эта информация используется после выполнения для определения прохождения / отказа / правильности приложения. Я хотел бы иметь возможность читать файл во время его записи, чтобы я мог выполнять эти проверки на наличие ошибок / ошибок / правильности в режиме реального времени.

Я предполагаю, что это можно сделать, но что за ошибки при использовании Java? Если чтение совпадает с записью, будет ли оно ждать новых записей до тех пор, пока файл не будет закрыт, или чтение вызовет исключение на этом этапе? Если последнее, что мне тогда делать?

Моя интуиция в настоящее время подталкивает меня к BufferedStreams. Это путь?

6.08.2008 23:57:10
эй, поскольку я сталкиваюсь с подобным сценарием, который я формулировал, если вы нашли лучшее решение, чем принятое?
Asaf David 11.05.2010 19:45:12
Я знаю, что это старый вопрос, но ради будущих читателей, не могли бы вы подробнее рассказать о вашем случае использования? Не имея больше информации, можно задаться вопросом, возможно, вы решаете не ту проблему.
user359996 17.11.2010 20:49:57
Изучите использование Tailer от Apache Commons IO. Он обрабатывает большинство крайних случаев.
Joshua 29.05.2012 16:28:31
Используйте базу данных. Эти сценарии «чтение файла в процессе его записи» заканчиваются слезами.
user207421 11.01.2013 23:49:18
@EJP - какую БД вы рекомендуете? Я предполагаю, что MySQL - хорошее начало?
Coffee 24.09.2015 17:41:01
9 ОТВЕТОВ
РЕШЕНИЕ

Не удалось заставить пример работать, 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. Да, я знаю, что все еще в каменном веке.

37
21.05.2017 15:42:13
Спасибо за добавление этого ... то, что я никогда не удосужился сделать. Я думаю, что ответ Blade о блокировке файла также хорош. Однако для этого требуется Java 6 (я думаю).
Anthony Cramp 1.10.2008 23:35:43
@JosephGordon - Вам придется перейти в эпоху дронов на днях ;-)
TungstenX 30.11.2016 09:36:43

Не Java как таковая, но вы можете столкнуться с проблемами, когда вы что-то записали в файл, но на самом деле это еще не было записано - это может быть где-то в кеше, и чтение из того же файла может фактически не дать вам новая информация.

Короткая версия - используйте flush () или любой другой системный вызов, чтобы убедиться, что ваши данные действительно записаны в файл.

Заметьте, я не говорю о дисковом кеше на уровне ОС - если ваши данные попадают сюда, они должны появиться в read () после этой точки. Может случиться так, что сам язык кеширует записи, ожидая, пока буфер не заполнится или файл не будет очищен / закрыт.

1
7.08.2008 00:31:47

Я никогда не пробовал, но вы должны написать тестовый пример, чтобы увидеть, будет ли работать чтение из потока после того, как вы дойдете до конца, независимо от того, есть ли еще данные, записанные в файл.

Есть ли причина, по которой вы не можете использовать потоковый поток ввода / вывода? Данные записываются и читаются из одного и того же приложения (если это так, у вас есть данные, зачем вам нужно читать из файла)?

В противном случае, возможно, прочитайте до конца файла, затем следите за изменениями и ищите, где вы остановились, и продолжайте ... хотя следите за условиями гонки.

0
7.08.2008 00:37:44

Ответ, кажется, "нет" ... и "да". Кажется, нет никакого реального способа узнать, открыт ли файл для записи другим приложением. Таким образом, чтение из такого файла будет продолжаться до тех пор, пока содержимое не будет исчерпано. Я воспользовался советом Майка и написал тестовый код:

Writer.java записывает строку в файл, а затем ждет, пока пользователь нажмет клавишу ввода, прежде чем записать другую строку в файл. Идея состоит в том, что он может быть запущен, а затем может быть запущен читатель, чтобы увидеть, как он справляется с «частичным» файлом. Читатель, который я написал, находится в 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);
    }
}

Нет гарантий, что этот кодекс является лучшей практикой.

Это оставляет возможность, предложенную Майком, периодически проверять, есть ли новые данные для чтения из файла. Затем требуется вмешательство пользователя для закрытия программы чтения файлов, когда определено, что чтение завершено. Или читатель должен быть осведомлен о содержимом файла и уметь определять и конец условия записи. Если бы содержимое было XML, конец документа мог бы использоваться, чтобы сигнализировать об этом.

3
7.08.2008 07:25:02

Вы также можете взглянуть на канал Java для блокировки части файла.

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

Эта функция FileChannelможет быть началом

lock(long position, long size, boolean shared) 

Вызов этого метода будет блокироваться, пока регион не будет заблокирован

5
1.09.2008 16:31:53

Есть Open Source Java Graphic Tail, который делает это.

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();
}
1
23.05.2017 12:10:41

Я полностью согласен с ответом Джошуа , Тайлер подходит для работы в этой ситуации. Вот пример:

Он записывает строку в файл каждые 150 мс, а читает этот же файл каждые 2500 мс.

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);
        }
    }
}
5
23.05.2017 12:34:50
Ваша ссылка на Tailer не работает.
Stealth Rabbi 22.07.2016 17:06:47
@StealthRabbi Лучше всего тогда найти правильную ссылку и отредактировать ответ.
igracia 15.11.2016 13:48:55

Если вы хотите прочитать файл во время его записи и только читать новый контент, то следующее поможет вам достичь того же.

Для запуска этой программы вы запустите ее из командной строки / окна терминала и передадите имя файла для чтения. Он прочитает файл, если вы не убьете программу.

Java 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();
    }
}
10
29.09.2015 19:08:15
Нет ли возможности того, что между временем чтения файла и временем взятия длины файла внешний процесс может добавить в файл больше данных. Если это так, это приведет к тому, что в процессе чтения будут отсутствовать данные, записанные в файл.
JohnC 18.07.2016 19:08:42
Этот код потребляет много ресурсов ЦП, потому что в цикле нет вызова thread.sleep. Не добавляя небольшую задержку, этот код обычно сильно загружает процессор.
ChaitanyaBhatt 11.05.2017 22:31:42

Вы не можете прочитать файл, который открывается из другого процесса, используя FileInputStream, FileReader или RandomAccessFile.

Но использование FileChannel напрямую будет работать:

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;
}
1
3.01.2016 12:09:17