【问题标题】:What is the fastest way to read a large number of small files into memory?将大量小文件读入内存的最快方法是什么?
【发布时间】:2010-10-12 03:27:30
【问题描述】:

我需要在每个服务器启动时读取大约 50 个文件,并将每个文本文件的表示形式放入内存中。每个文本文件都有自己的字符串(字符串持有者最好使用哪种类型?)。

将文件读入内存的最快方法是什么,以及保存文本以便我可以在内存中操作它(主要是搜索和替换)的最佳数据结构/类型是什么?

谢谢

【问题讨论】:

  • 文本文件采用哪种编码方式? ASCII? UTF8?这将在实施上产生一些差异。

标签: java performance file types io


【解决方案1】:

内存映射文件将是最快的......像这样:

    final File             file;
    final FileChannel      channel;
    final MappedByteBuffer buffer;

    file    = new File(fileName);
    fin     = new FileInputStream(file);
    channel = fin.getChannel();
    buffer  = channel.map(MapMode.READ_ONLY, 0, file.length());

然后继续从字节缓冲区中读取。

这将比FileInputStreamFileReader 快得多。

编辑:

对此进行一些调查后发现,根据您的操作系统,您最好改用新的BufferedInputStream(new FileInputStream(file))。然而,一次将整个内容全部读入 char[] 文件的大小听起来是最糟糕的方式。

所以BufferedInputStream 应该在所有平台上提供大致一致的性能,而内存映射文件可能会变慢或变快,具体取决于底层操作系统。与所有对性能至关重要的东西一样,您应该测试您的代码,看看什么效果最好。

编辑:

好的,这里有一些测试(第一个测试做了两次以将文件放入磁盘缓存)。

我在 rt.jar 类文件上运行它,解压到硬盘上,这是在 Windows 7 beta x64 下。即 16784 个文件,总共 94,706,637 个字节。

首先是结果...

(记住第一个是重复获取磁盘缓存设置)

  • 阵列测试

    • 时间 = 83016
    • 字节 = 118641472
  • 数组测试

    • 时间 = 46570
    • 字节 = 118641472
  • DataInputByteAtATime

    • 时间 = 74735
    • 字节 = 118641472
  • DataInputReadFully

    • 时间 = 8953
    • 字节 = 118641472
  • 内存映射

    • 时间 = 2320
    • 字节 = 118641472

这里是代码...

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.HashSet;
import java.util.Set;

public class Main
{
    public static void main(final String[] argv)
    {
        ArrayTest.main(argv);
        ArrayTest.main(argv);
        DataInputByteAtATime.main(argv);
        DataInputReadFully.main(argv);
        MemoryMapped.main(argv);
    }
}

abstract class Test
{
    public final void run(final File root)
    {
        final Set<File> files;
        final long      size;
        final long      start;
        final long      end;
        final long      total;

        files = new HashSet<File>();
        getFiles(root, files);

        start = System.currentTimeMillis();

        size = readFiles(files);

        end = System.currentTimeMillis();
        total = end - start;

        System.out.println(getClass().getName());
        System.out.println("time  = " + total);
        System.out.println("bytes = " + size);
    }

    private void getFiles(final File      dir,
                          final Set<File> files)
    {
        final File[] childeren;

        childeren = dir.listFiles();

        for(final File child : childeren)
        {
            if(child.isFile())
            {
                files.add(child);
            }
            else
            {
                getFiles(child, files);
            }
        }
    }

    private long readFiles(final Set<File> files)
    {
        long size;

        size = 0;

        for(final File file : files)
        {
            size += readFile(file);
        }

        return (size);
    }

    protected abstract long readFile(File file);
}

class ArrayTest
    extends Test
{
    public static void main(final String[] argv)
    {
        final Test test;

        test = new ArrayTest();
        test.run(new File(argv[0]));
    }

    protected long readFile(final File file)
    {
        InputStream stream;

        stream = null;

        try
        {
            final byte[] data;
            int          soFar;
            int          sum;

            stream = new BufferedInputStream(new FileInputStream(file));
            data   = new byte[(int)file.length()];
            soFar  = 0;

            do
            {
                soFar += stream.read(data, soFar, data.length - soFar);
            }
            while(soFar != data.length);

            sum = 0;

            for(final byte b : data)
            {
                sum += b;
            }

            return (sum);
        }
        catch(final IOException ex)
        {
            ex.printStackTrace();
        }
        finally
        {
            if(stream != null)
            {
                try
                {
                    stream.close();
                }
                catch(final IOException ex)
                {
                    ex.printStackTrace();
                }
            }
        }

        return (0);
    }
}

class DataInputByteAtATime
    extends Test
{
    public static void main(final String[] argv)
    {
        final Test test;

        test = new DataInputByteAtATime();
        test.run(new File(argv[0]));
    }

    protected long readFile(final File file)
    {
        DataInputStream stream;

        stream = null;

        try
        {
            final int fileSize;
            int       sum;

            stream   = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
            fileSize = (int)file.length();
            sum      = 0;

            for(int i = 0; i < fileSize; i++)
            {
                sum += stream.readByte();
            }

            return (sum);
        }
        catch(final IOException ex)
        {
            ex.printStackTrace();
        }
        finally
        {
            if(stream != null)
            {
                try
                {
                    stream.close();
                }
                catch(final IOException ex)
                {
                    ex.printStackTrace();
                }
            }
        }

        return (0);
    }
}

class DataInputReadFully
    extends Test
{
    public static void main(final String[] argv)
    {
        final Test test;

        test = new DataInputReadFully();
        test.run(new File(argv[0]));
    }

    protected long readFile(final File file)
    {
        DataInputStream stream;

        stream = null;

        try
        {
            final byte[] data;
            int          sum;

            stream = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
            data   = new byte[(int)file.length()];
            stream.readFully(data);

            sum = 0;

            for(final byte b : data)
            {
                sum += b;
            }

            return (sum);
        }
        catch(final IOException ex)
        {
            ex.printStackTrace();
        }
        finally
        {
            if(stream != null)
            {
                try
                {
                    stream.close();
                }
                catch(final IOException ex)
                {
                    ex.printStackTrace();
                }
            }
        }

        return (0);
    }
}

class DataInputReadInChunks
    extends Test
{
    public static void main(final String[] argv)
    {
        final Test test;

        test = new DataInputReadInChunks();
        test.run(new File(argv[0]));
    }

    protected long readFile(final File file)
    {
        DataInputStream stream;

        stream = null;

        try
        {
            final byte[] data;
            int          size;
            final int    fileSize;
            int          sum;

            stream   = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
            fileSize = (int)file.length();
            data     = new byte[512];
            size     = 0;
            sum      = 0;

            do
            {
                size += stream.read(data);

                sum = 0;

                for(int i = 0; i < size; i++)
                {
                    sum += data[i];
                }
            }
            while(size != fileSize);

            return (sum);
        }
        catch(final IOException ex)
        {
            ex.printStackTrace();
        }
        finally
        {
            if(stream != null)
            {
                try
                {
                    stream.close();
                }
                catch(final IOException ex)
                {
                    ex.printStackTrace();
                }
            }
        }

        return (0);
    }
}
class MemoryMapped
    extends Test
{
    public static void main(final String[] argv)
    {
        final Test test;

        test = new MemoryMapped();
        test.run(new File(argv[0]));
    }

    protected long readFile(final File file)
    {
        FileInputStream stream;

        stream = null;

        try
        {
            final FileChannel      channel;
            final MappedByteBuffer buffer;
            final int              fileSize;
            int                    sum;

            stream   = new FileInputStream(file);
            channel  = stream.getChannel();
            buffer   = channel.map(MapMode.READ_ONLY, 0, file.length());
            fileSize = (int)file.length();
            sum      = 0;

            for(int i = 0; i < fileSize; i++)
            {
                sum += buffer.get();
            }

            return (sum);
        }
        catch(final IOException ex)
        {
            ex.printStackTrace();
        }
        finally
        {
            if(stream != null)
            {
                try
                {
                    stream.close();
                }
                catch(final IOException ex)
                {
                    ex.printStackTrace();
                }
            }
        }

        return (0);
    }
}

【讨论】:

  • 有趣!您对这两种方法有基准或比较吗?
  • 我有一些代码(早已不复存在)解析 rt.jar (6000+) 中的每个类文件。使用 FileInputStream(用 BufferedIputStream 包装)需要 30 秒,使用内存映射文件也需要 4 秒。除了读取字节的方式之外,代码没有任何区别。
  • 在做之前我确实将所有文件从 JAR 提取到文件系统中。
  • 这将读取字节而不一定是字符数据,对吗?
  • 您可以通过 ByteBuffer.asCharBuffer 使用 CharBuffer。此外,速度将非常依赖于操作系统 - nio 与底层操作系统紧密集成(更新我的答案)
【解决方案2】:

最有效的方法是:

  • 确定文件长度 (File.length())
  • 创建一个大小相同(或稍大)的字符缓冲区
  • 确定文件的编码
  • 使用new InputStreamReader (new FileInputStream(file), encoding)阅读
  • 通过一次 read() 调用将 while 文件读入缓冲区。请注意, read() 可能会提前返回(没有读取整个文件)。在这种情况下,使用偏移量再次调用它以读取下一批。
  • 创建字符串:new String(buffer)

如果您需要在启动时搜索&替换一次,请使用 String.replaceAll()。

如果需要反复做,可以考虑使用StringBuilder。它没有 replaceAll(),但您可以使用它来操作字符数组(-> 不分配内存)。

也就是说:

  1. 使您的代码尽可能简短。
  2. 衡量性能
  3. 太慢了,修一下。

如果只需要 0.1 秒的执行时间,就没有理由浪费大量时间让这段代码快速运行。

如果您仍然有性能问题,请考虑将所有文本文件放入一个 JAR 中,将其添加到类路径中并使用 Class.getResourceAsStream() 来读取文件。从 Java 类路径加载东西是高度优化的。

【讨论】:

  • 如果我使用 Class.getResourceAsStream() 加载所有文本文件,我如何迭代将文件扔到 jar 中?
  • java.util.ZipFile 将让您处理 JAR 上的文件(JAR 只是一个 zip 文件)。
  • 使用 ZipFile 或迭代文件名列表(而不是尝试迭代资源)。
  • 无法一次调用 read - 必须循环它,因为 read 可能无法一次性读取整个文件
  • @TofuBeer 是对的;您应该循环检查实际读取了多少字节。
【解决方案3】:

这在很大程度上取决于文本文件的内部结构以及您打算如何处理它们。

文件是键值字典(即“属性”文件)吗? XML? JSON?你有这些的标准结构。

如果它们有正式的结构,您也可以使用 JavaCC 来构建文件的对象表示。

否则,如果它们只是数据块,那么读取文件并将它们放入字符串中。

编辑:关于搜索和替换——只使用String's replaceAll function

【讨论】:

    【解决方案4】:

    在谷歌上搜索Java IO 速度的现有测试后,我必须说TofuBear 的测试用例让我大开眼界。你必须在你自己的平台上运行他的测试,看看什么对你来说是最快的。

    在运行他的测试并添加一些我自己的测试后(感谢 TofuBear 发布他的原始代码),使用自己的自定义缓冲区与使用 BufferedInputStream 相比,您似乎可以获得更快的速度。

    令我沮丧的是,NIO ByteBuffer 表现不佳。

    注意:静态 byte[] 缓冲区缩短了几毫秒,但静态 ByteBuffers 实际上增加了处理时间! 代码有什么问题吗??

    我添加了一些测试:

    1. ArrayTest_CustomBuffering(将数据直接读取到我自己的缓冲区中)

    2. ArrayTest_CustomBuffering_StaticBuffer(将数据读取到一开始只创建一次的静态缓冲区中)

    3. FileChannelArrayByteBuffer(使用 NIO ByteBuffer 并包装您自己的 byte[] 数组)

    4. FileChannelAllocateByteBuffer(将 NIO ByteBuffer 与 .allocate 一起使用)

    5. FileChannelAllocateByteBuffer_StaticBuffer(与 4 相同,但带有静态缓冲区)

    6. FileChannelAllocateDirectByteBuffer(将 NIO ByteBuffer 与 .allocateDirect 一起使用)

    7. FileChannelAllocateDirectByteBuffer_StaticBuffer(与 6 相同,但带有静态缓冲区)

    这是我的结果:在提取的 rt.jar 上使用 Windows Vista 和 jdk1.6.0_13: 数组测试
    时间 = 2075
    字节 = 2120336424
    数组测试
    时间 = 2044
    字节 = 2120336424
    ArrayTest_CustomBuffering
    时间 = 1903
    字节 = 2120336424
    ArrayTest_CustomBuffering_StaticBuffer
    时间 = 1872
    字节 = 2120336424
    DataInputByteAtATime
    时间 = 2668
    字节 = 2120336424
    DataInputReadFully
    时间 = 2028
    字节 = 2120336424
    内存映射
    时间 = 2901
    字节 = 2120336424
    FileChannelArrayByteBuffer
    时间 = 2371
    字节 = 2120336424
    FileChannelAllocateByteBuffer
    时间 = 2356
    字节 = 2120336424
    FileChannelAllocateByteBuffer_StaticBuffer
    时间 = 2668
    字节 = 2120336424
    FileChannelAllocateDirectByteBuffer
    时间 = 2512
    字节 = 2120336424
    FileChannelAllocateDirectByteBuffer_StaticBuffer
    时间 = 2590
    字节 = 2120336424

    我破解版的 TofuBear 代码:

    import java.io.BufferedInputStream;
    import java.io.DataInputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.nio.MappedByteBuffer;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    import java.nio.channels.FileChannel.MapMode;
    import java.util.HashSet;
    import java.util.Set;
    public class Main { 
        public static void main(final String[] argv)     { 
            ArrayTest.mainx(argv);
            ArrayTest.mainx(argv);
            ArrayTest_CustomBuffering.mainx(argv);
            ArrayTest_CustomBuffering_StaticBuffer.mainx(argv);
            DataInputByteAtATime.mainx(argv);
            DataInputReadFully.mainx(argv);
            MemoryMapped.mainx(argv);
            FileChannelArrayByteBuffer.mainx(argv);
            FileChannelAllocateByteBuffer.mainx(argv);
            FileChannelAllocateByteBuffer_StaticBuffer.mainx(argv);
            FileChannelAllocateDirectByteBuffer.mainx(argv);
            FileChannelAllocateDirectByteBuffer_StaticBuffer.mainx(argv);
         } 
     } 
    abstract class Test { 
        static final int BUFF_SIZE = 20971520;
        static final byte[] StaticData = new byte[BUFF_SIZE];
        static final ByteBuffer StaticBuffer =ByteBuffer.allocate(BUFF_SIZE);
        static final ByteBuffer StaticDirectBuffer = ByteBuffer.allocateDirect(BUFF_SIZE);
        public final void run(final File root)     { 
            final Set<File> files;
            final long      size;
            final long      start;
            final long      end;
            final long      total;
            files = new HashSet<File>();
            getFiles(root, files);
            start = System.currentTimeMillis();
            size = readFiles(files);
            end = System.currentTimeMillis();
            total = end - start;
            System.out.println(getClass().getName());
            System.out.println("time  = " + total);
            System.out.println("bytes = " + size);
         } 
        private void getFiles(final File dir,final Set<File> files)     { 
            final File[] childeren;
            childeren = dir.listFiles();
            for(final File child : childeren)         { 
                if(child.isFile())             { 
                    files.add(child);
                 } 
                else             { 
                    getFiles(child, files);
                 } 
             } 
         } 
        private long readFiles(final Set<File> files)     { 
            long size;
            size = 0;
            for(final File file : files)         { 
                size += readFile(file);
             } 
            return (size);
         } 
        protected abstract long readFile(File file);
     } 
    class ArrayTest    extends Test { 
        public static void mainx(final String[] argv)     { 
            final Test test;
            test = new ArrayTest();
            test.run(new File(argv[0]));
         } 
        protected long readFile(final File file)     { 
            InputStream stream;
            stream = null;
            try         { 
                final byte[] data;
                int          soFar;
                int          sum;
                stream = new BufferedInputStream(new FileInputStream(file));
                data   = new byte[(int)file.length()];
                soFar  = 0;
                do             { 
                    soFar += stream.read(data, soFar, data.length - soFar);
                 } 
                while(soFar != data.length);
                sum = 0;
                for(final byte b : data)             { 
                    sum += b;
                 } 
                return (sum);
             } 
            catch(final IOException ex)         { 
                ex.printStackTrace();
             } 
            finally         { 
                if(stream != null)             { 
                    try                 { 
                        stream.close();
                     } 
                    catch(final IOException ex)                 { 
                        ex.printStackTrace();
                     } 
                 } 
             } 
            return (0);
         } 
     } 
    
     class ArrayTest_CustomBuffering    extends Test { 
        public static void mainx(final String[] argv)     { 
            final Test test;
            test = new ArrayTest_CustomBuffering();
            test.run(new File(argv[0]));
         } 
        protected long readFile(final File file)     { 
            InputStream stream;
            stream = null;
            try         { 
                final byte[] data;
                int          soFar;
                int          sum;
                stream = new FileInputStream(file);
                data   = new byte[(int)file.length()];
                soFar  = 0;
                do             { 
                    soFar += stream.read(data, soFar, data.length - soFar);
                 } 
                while(soFar != data.length);
                sum = 0;
                for(final byte b : data)             { 
                    sum += b;
                 } 
                return (sum);
             } 
            catch(final IOException ex)         { 
                ex.printStackTrace();
             } 
            finally         { 
                if(stream != null)             { 
                    try                 { 
                        stream.close();
                     } 
                    catch(final IOException ex)                 { 
                        ex.printStackTrace();
                     } 
                 } 
             } 
            return (0);
         } 
     }
    
     class ArrayTest_CustomBuffering_StaticBuffer    extends Test { 
    
    
    
        public static void mainx(final String[] argv)     { 
            final Test test;
            test = new ArrayTest_CustomBuffering_StaticBuffer();
            test.run(new File(argv[0]));
         } 
        protected long readFile(final File file)     { 
            InputStream stream;
            stream = null;
            try         { 
                int          soFar;
                int          sum;
                final int    fileSize;
                stream = new FileInputStream(file);
                fileSize = (int)file.length();
                soFar  = 0;
                do             { 
                    soFar += stream.read(StaticData, soFar, fileSize - soFar);
                 } 
                while(soFar != fileSize);
                sum = 0;
                for(int i=0;i<fileSize;i++)             { 
                    sum += StaticData[i];
                 } 
                return (sum);
             } 
            catch(final IOException ex)         { 
                ex.printStackTrace();
             } 
            finally         { 
                if(stream != null)             { 
                    try                 { 
                        stream.close();
                     } 
                    catch(final IOException ex)                 { 
                        ex.printStackTrace();
                     } 
                 } 
             } 
            return (0);
         } 
     }
    
    class DataInputByteAtATime    extends Test { 
        public static void mainx(final String[] argv)     { 
            final Test test;
            test = new DataInputByteAtATime();
            test.run(new File(argv[0]));
         } 
        protected long readFile(final File file)     { 
            DataInputStream stream;
            stream = null;
            try         { 
                final int fileSize;
                int       sum;
                stream   = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
                fileSize = (int)file.length();
                sum      = 0;
                for(int i = 0; i < fileSize; i++)             { 
                    sum += stream.readByte();
                 } 
                return (sum);
             } 
            catch(final IOException ex)         { 
                ex.printStackTrace();
             } 
            finally         { 
                if(stream != null)             { 
                    try                 { 
                        stream.close();
                     } 
                    catch(final IOException ex)                 { 
                        ex.printStackTrace();
                     } 
                 } 
             } 
            return (0);
         } 
     } 
    class DataInputReadFully    extends Test { 
        public static void mainx(final String[] argv)     { 
            final Test test;
            test = new DataInputReadFully();
            test.run(new File(argv[0]));
         } 
        protected long readFile(final File file)     { 
            DataInputStream stream;
            stream = null;
            try         { 
                final byte[] data;
                int          sum;
                stream = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
                data   = new byte[(int)file.length()];
                stream.readFully(data);
                sum = 0;
                for(final byte b : data)             { 
                    sum += b;
                 } 
                return (sum);
             } 
            catch(final IOException ex)         { 
                ex.printStackTrace();
             } 
            finally         { 
                if(stream != null)             { 
                    try                 { 
                        stream.close();
                     } 
                    catch(final IOException ex)                 { 
                        ex.printStackTrace();
                     } 
                 } 
             } 
            return (0);
         } 
     } 
    class DataInputReadInChunks    extends Test { 
        public static void mainx(final String[] argv)     { 
            final Test test;
            test = new DataInputReadInChunks();
            test.run(new File(argv[0]));
         } 
        protected long readFile(final File file)     { 
            DataInputStream stream;
            stream = null;
            try         { 
                final byte[] data;
                int          size;
                final int    fileSize;
                int          sum;
                stream   = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
                fileSize = (int)file.length();
                data     = new byte[512];
                size     = 0;
                sum      = 0;
                do             { 
                    size += stream.read(data);
                    sum = 0;
                    for(int i = 0;
     i < size;
     i++)                 { 
                        sum += data[i];
                     } 
                 } 
                while(size != fileSize);
                return (sum);
             } 
            catch(final IOException ex)         { 
                ex.printStackTrace();
             } 
            finally         { 
                if(stream != null)             { 
                    try                 { 
                        stream.close();
                     } 
                    catch(final IOException ex)                 { 
                        ex.printStackTrace();
                     } 
                 } 
             } 
            return (0);
         } 
     } 
    class MemoryMapped    extends Test { 
        public static void mainx(final String[] argv)     { 
            final Test test;
            test = new MemoryMapped();
            test.run(new File(argv[0]));
         } 
        protected long readFile(final File file)     { 
            FileInputStream stream;
            stream = null;
            try         { 
                final FileChannel      channel;
                final MappedByteBuffer buffer;
                final int              fileSize;
                int                    sum;
                stream   = new FileInputStream(file);
                channel  = stream.getChannel();
                buffer   = channel.map(MapMode.READ_ONLY, 0, file.length());
                fileSize = (int)file.length();
                sum      = 0;
    
                for(int i = 0; i < fileSize; i++)             { 
                    sum += buffer.get();
                 } 
                return (sum);
             } 
            catch(final IOException ex)         { 
                ex.printStackTrace();
             } 
            finally         { 
                if(stream != null)             { 
                    try                 { 
                        stream.close();
                     } 
                    catch(final IOException ex)                 { 
                        ex.printStackTrace();
                     } 
                 } 
             } 
            return (0);
         } 
     } 
    
     class FileChannelArrayByteBuffer    extends Test { 
        public static void mainx(final String[] argv)     { 
            final Test test;
            test = new FileChannelArrayByteBuffer();
            test.run(new File(argv[0]));
         } 
        protected long readFile(final File file)     { 
            FileInputStream stream;
            stream = null;
            try         { 
                final byte[] data;
                final FileChannel      channel;
                final ByteBuffer       buffer;
                int                    nRead=0;
                final int              fileSize;
                int                    sum;
                stream = new  FileInputStream(file);
                data   = new byte[(int)file.length()];
                buffer = ByteBuffer.wrap(data);
    
                channel  = stream.getChannel();
                fileSize = (int)file.length();
                nRead += channel.read(buffer);
    
                buffer.rewind();
                sum      = 0;
                for(int i = 0; i < fileSize; i++)             { 
                    sum += buffer.get();
                 } 
                return (sum);
             } 
            catch(final IOException ex)         { 
                ex.printStackTrace();
             } 
            finally         { 
                if(stream != null)             { 
                    try                 { 
                        stream.close();
                     } 
                    catch(final IOException ex)                 { 
                        ex.printStackTrace();
                     } 
                 } 
             } 
            return (0);
         } 
     } 
    
     class FileChannelAllocateByteBuffer    extends Test { 
        public static void mainx(final String[] argv)     { 
            final Test test;
            test = new FileChannelAllocateByteBuffer();
            test.run(new File(argv[0]));
         } 
        protected long readFile(final File file)     { 
            FileInputStream stream;
            stream = null;
            try         { 
                final byte[] data;
                final FileChannel      channel;
                final ByteBuffer       buffer;
                int                    nRead=0;
                final int              fileSize;
                int                    sum;
                stream = new  FileInputStream(file);
                //data   = new byte[(int)file.length()];
                buffer = ByteBuffer.allocate((int)file.length());
    
                channel  = stream.getChannel();
                fileSize = (int)file.length();
                nRead += channel.read(buffer);
    
                buffer.rewind();
                sum      = 0;
                for(int i = 0; i < fileSize; i++)             { 
                    sum += buffer.get();
                 } 
                return (sum);
             } 
            catch(final IOException ex)         { 
                ex.printStackTrace();
             } 
            finally         { 
                if(stream != null)             { 
                    try                 { 
                        stream.close();
                     } 
                    catch(final IOException ex)                 { 
                        ex.printStackTrace();
                     } 
                 } 
             } 
            return (0);
         } 
     } 
    
     class FileChannelAllocateDirectByteBuffer    extends Test { 
        public static void mainx(final String[] argv)     { 
            final Test test;
            test = new FileChannelAllocateDirectByteBuffer();
            test.run(new File(argv[0]));
         } 
        protected long readFile(final File file)     { 
            FileInputStream stream;
            stream = null;
            try         { 
                final byte[] data;
                final FileChannel      channel;
                final ByteBuffer       buffer;
                int                    nRead=0;
                final int              fileSize;
                int                    sum;
                stream = new  FileInputStream(file);
                //data   = new byte[(int)file.length()];
                buffer = ByteBuffer.allocateDirect((int)file.length());
    
                channel  = stream.getChannel();
                fileSize = (int)file.length();
                nRead += channel.read(buffer);
    
                buffer.rewind();
                sum      = 0;
                for(int i = 0; i < fileSize; i++)             { 
                    sum += buffer.get();
                 } 
                return (sum);
             } 
            catch(final IOException ex)         { 
                ex.printStackTrace();
             } 
            finally         { 
                if(stream != null)             { 
                    try                 { 
                        stream.close();
                     } 
                    catch(final IOException ex)                 { 
                        ex.printStackTrace();
                     } 
                 } 
             } 
            return (0);
         } 
     }
    
     class FileChannelAllocateByteBuffer_StaticBuffer    extends Test { 
        public static void mainx(final String[] argv)     { 
            final Test test;
            test = new FileChannelAllocateByteBuffer_StaticBuffer();
            test.run(new File(argv[0]));
         } 
        protected long readFile(final File file)     { 
            FileInputStream stream;
            stream = null;
            try         { 
                final byte[] data;
                final FileChannel      channel;
                int                    nRead=0;
                final int              fileSize;
                int                    sum;
                stream = new  FileInputStream(file);
                //data   = new byte[(int)file.length()];
                StaticBuffer.clear();
                StaticBuffer.limit((int)file.length());
                channel  = stream.getChannel();
                fileSize = (int)file.length();
                nRead += channel.read(StaticBuffer);
    
                StaticBuffer.rewind();
                sum      = 0;
                for(int i = 0; i < fileSize; i++)             { 
                    sum += StaticBuffer.get();
                 } 
                return (sum);
             } 
            catch(final IOException ex)         { 
                ex.printStackTrace();
             } 
            finally         { 
                if(stream != null)             { 
                    try                 { 
                        stream.close();
                     } 
                    catch(final IOException ex)                 { 
                        ex.printStackTrace();
                     } 
                 } 
             } 
            return (0);
         } 
     }
    
     class FileChannelAllocateDirectByteBuffer_StaticBuffer    extends Test { 
        public static void mainx(final String[] argv)     { 
            final Test test;
            test = new FileChannelAllocateDirectByteBuffer_StaticBuffer();
            test.run(new File(argv[0]));
         } 
        protected long readFile(final File file)     { 
            FileInputStream stream;
            stream = null;
            try         { 
                final byte[] data;
                final FileChannel      channel;
                int                    nRead=0;
                final int              fileSize;
                int                    sum;
                stream = new  FileInputStream(file);
                //data   = new byte[(int)file.length()];
                StaticDirectBuffer.clear();
                StaticDirectBuffer.limit((int)file.length());
                channel  = stream.getChannel();
                fileSize = (int)file.length();
                nRead += channel.read(StaticDirectBuffer);
    
                StaticDirectBuffer.rewind();
                sum      = 0;
                for(int i = 0; i < fileSize; i++)             { 
                    sum += StaticDirectBuffer.get();
                 } 
                return (sum);
             } 
            catch(final IOException ex)         { 
                ex.printStackTrace();
             } 
            finally         { 
                if(stream != null)             { 
                    try                 { 
                        stream.close();
                     } 
                    catch(final IOException ex)                 { 
                        ex.printStackTrace();
                     } 
                 } 
             } 
            return (0);
         } 
     }
    

    【讨论】:

    • 时代对我来说很可疑。我不确定我是否相信“仅”几秒钟的时间比较。 JVM 需要时间来启动。我会使用更大的文件或更多的迭代。正如 tofubeer 指出的那样,您还需要在开始“真实”计时之前包含至少一个额外迭代的循环,以启动磁盘缓存并让 JVM 的 JIT 完成其花哨的工作。
    • 我确实保留了 TofuBeer 的“启动”副本作为测试中的第一次迭代。这些文件已从先前的运行中缓存。我在 XP 机器上重新运行测试并得出类似的结果。当重用静态缓冲区与为每个文件创建一个新缓冲区时,我真的对速度下降感到困惑。也许这是底层 JVM 的优化?不确定..我宁愿相信这是编写代码的问题。我想我可能会通过 JAVA API 中的底层源来查看 NIO 通道与 FileInputStreams 的情况。感谢您的输入
    【解决方案5】:

    任何传统方法都会在速度上受到限制。我不确定您是否会看到从一种方法到另一种方法的很大差异。

    我会专注于可以使整个操作更快的商业技巧。

    例如,如果您读取所有文件并将它们与每个原始文件的时间戳一起存储在一个文件中,那么您可以检查是否有任何文件已更改而无需实际打开它们。 (换句话说,一个简单的缓存)。

    如果您的问题是快速启动 GUI,您可能会找到在显示第一个屏幕后在后台线程中打开文件的方法。

    操作系统可以很好地处理文件,如果这是批处理过程的一部分(没有用户 I/O),您可以从一个批处理文件开始,在启动 java 之前将所有文件附加到一个大文件中,使用一些东西像这样:

    echo "file1" > file.all
    type "file1" >> file.all
    echo "file2" >> file.all
    type "file2" >> file.all
    

    然后打开 file.all(我不确定这会快多少,但这可能是我刚才所说的条件下最快的方法)

    我想我只是说,通常情况下,速度问题的解决方案通常需要稍微扩展您的观点并使用新参数完全重新考虑解决方案。对现有算法的修改通常只会以牺牲可读性为代价来提高速度。

    【讨论】:

      【解决方案6】:

      您应该能够使用 Commons IO FileUtils.readFileToString(File) 等标准工具在一秒钟内读取所有文件

      您也可以使用 writeStringToFile(File, String) 来保存修改后的文件。

      http://commons.apache.org/io/api-release/index.html?org/apache/commons/io/FileUtils.html

      顺便说一句:50 不是很多文件。一台典型的 PC 可以有 100K 或更多文件。

      【讨论】:

        猜你喜欢
        • 2012-04-22
        • 1970-01-01
        • 1970-01-01
        • 2013-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-25
        • 1970-01-01
        相关资源
        最近更新 更多