Linux 下的 Java RandomAccessFile.java 无法正常工作

标签 java linux tail randomaccessfile

我正在尝试在 java 中实现简单的 tail -f linux 命令。这是我的代码。

try
    {
        // position within the file
        File file = new File("/home/curuk/monitored/log.txt");
        RandomAccessFile raFile = new RandomAccessFile(file, "r");
        long last = file.lastModified(); // The last time the file was checked for changes
        long position = file.length();
        while (true)
        {
            if (file.lastModified() > last)
            {
                last = file.lastModified();
                readFromFile(raFile, (int) position, (int) (file.length() - position));
                position = file.length();
            }
            Thread.sleep(1000);
        }
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }

private byte[] readFromFile(RandomAccessFile file, int position, int size) throws IOException
    {
        file.seek(position);
        byte[] bytes = new byte[size];
        System.err.println(file.read(bytes, 0, size));
        String s = new String(bytes);
        System.err.println(s);
        return bytes;
    }

问题是在 linux 操作系统下,file.read(bytes, 0, size) 总是返回 -1,而在 Windows 下,相同的代码片段工作得很好(总是打印新行).

编辑:

我通过在每次迭代中添加 raFile = new RandomAccessFile(file, "r"); 解决了这个问题。

while (true)
            {
                raFile = new RandomAccessFile(file, "r");
                if (file.lastModified() > last)
                {
                    last = file.lastModified();
                    readFromFile(raFile, (int) position, (int) (file.length() - position));
                    position = file.length();
                }
                Thread.sleep(1000);
            }

不知道为什么,但现在在 Linux 下也能正常工作。 谢谢你们的努力

最佳答案

这是一个完全基于 Java 7 的解决方案,使用了新的 WatchService 基础设施:

有效,但相当粗糙...

public final class Baz
{
    public static void main(final String... args)
        throws IOException
    {
        // Get paths to the containing directory and the file we want to spy
        final Path dir = Paths.get("/tmp");
        final Path file = dir.resolve("foo.txt");

        // Get the watch service for our default filesystem
        // We are only interested in modifications and deletions
        final WatchService service = FileSystems.getDefault().newWatchService();
        dir.register(service, StandardWatchEventKinds.ENTRY_MODIFY,
            StandardWatchEventKinds.ENTRY_DELETE);

        // Get a charset decoder -- we will be reading bytes from the file,
        // we will need to decode them to a string
        final CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder()
            .onMalformedInput(CodingErrorAction.IGNORE)
            .onUnmappableCharacter(CodingErrorAction.IGNORE);


        try (
            // Open a SeekableByteChannel to the file -- read only
            final SeekableByteChannel channel
                = Files.newByteChannel(file, StandardOpenOption.READ);
        ) {
            long oldSize;
            while (true) {
                // Get the current size of our file
                oldSize = channel.size();
                try {
                    // Grab a key
                    final WatchKey key = service.poll(1L, TimeUnit.SECONDS);
                    if (key == null) // No events...
                        continue;

                    for (final WatchEvent<?> e: key.pollEvents()) {
                        @SuppressWarnings("unchecked")
                        final WatchEvent<Path> event = (WatchEvent<Path>) e;

                        // What kind of event, to whom it applies
                        final WatchEvent.Kind<Path> kind = event.kind();
                        final Path context = dir.resolve(event.context());

                        // If not to us, we don't care
                        if (!context.equals(file))
                            continue;

                        // If our file has disappeared, exit
                        if (kind == StandardWatchEventKinds.ENTRY_DELETE) {
                            System.err.println("File deleted");
                            System.exit(0);
                        }

                        // OK, so it's a modification, and it is our file: read the tail
                        doRead(oldSize, decoder, channel);
                    }
                    // Reset the key for the next batch of events
                    key.reset();
                } catch (InterruptedException e) {
                    // service.poll() interrupted: get out
                    break;
                }
            }
        }
    }

    private static void doRead(final long oldSize, final CharsetDecoder decoder,
        final SeekableByteChannel channel)
        throws IOException
    {
        final long newSize = channel.size();
        if (newSize <= oldSize)
            return;
        final int bufsize = (int) (newSize - oldSize);
        final ByteBuffer buf = ByteBuffer.allocate(bufsize);
        channel.position(oldSize).read(buf);
        buf.rewind();
        decoder.reset();
        System.out.println(decoder.decode(buf).toString());
    }
}

关于Linux 下的 Java RandomAccessFile.java 无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22485267/

相关文章:

unix - Unix 中的 execl 行为

java - Jersey JSON 应用程序构建失败

Java:为什么 7/-3 是 -2?

c++ - 重载内存映射文件加载器 (C++)

linux - 使用 cabal-install 安装 netcore 时出错

hadoop - 相当于 'hadoop fs -tail -f' 的程序

java - 将事物从 Array 更改为 ArrayList

java - 如何通过按钮单击事件在 JPanel 中绘制矩形

linux - bash pid 和 $$ 之间的区别

perl - 如何在读取事件中捕获 File::Tail 异常