如何快速地将大量小文件读入内存?

21

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

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

谢谢


1
文本文件使用哪种编码?ASCII?UTF8?这将对实现产生一些差异。 - Horcrux7
6个回答

31

内存映射文件是最快的...类似这样:

    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个文件,总共94606637字节。

首先是结果...

(请记住,第一个测试需要重复一次以设置磁盘缓存)

  • ArrayTest

    • time = 83016
    • bytes = 118641472
  • ArrayTest

    • time = 46570
    • bytes = 118641472
  • DataInputByteAtATime

    • time = 74735
    • bytes = 118641472
  • DataInputReadFully

    • time = 8953
    • bytes = 118641472
  • MemoryMapped

    • time = 2320
    • bytes = 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);
    }
}

有趣!你有这两种方法之间的基准或比较吗? - Hosam Aly
我曾经有一些代码(已经消失了),它解析了rt.jar(6000+)中的每个类文件。使用FileInputStream(包装了BufferedInputStream)花费了30秒,而使用内存映射文件只需4秒。除了读取字节的方式之外,代码没有任何区别。 - TofuBeer
在执行此操作之前,我已将JAR中的所有文件提取到文件系统中。 - TofuBeer
就像你所说的那样,内存映射在某些操作系统上可能需要很长时间。因此,对于小文件来说,这可能不是一个好主意。 - kohlerm
使用BufferedInputStream时需要注意缓冲区大小。默认值为8192,但是如果将其设置得更小(我读取的是非常小的文件),可以大大提高速度。 - Erk
显示剩余7条评论

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

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

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

话虽如此:

  1. 尽可能使代码简短而简单。
  2. 测量性能
  3. 如果太慢,请修复它。

如果执行时间只需0.1秒,没有必要花费大量时间使此代码运行速度更快。

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


如果我使用Class.getResourceAsStream()加载所有文本文件,如何遍历JAR包中的文件? - user63898
java.util.ZipFile 可以让您处理 JAR 文件(JAR 文件只是一个 zip 文件)。 - TofuBeer
无法进行单次读取 - 必须循环读取,因为读取可能无法一次性读取整个文件。 - TofuBeer
使用 String.replaceAll() 绝对不是一个好主意。它不会在原地替换字符串,而是会分配新的字符串。 - kohlerm
由于在Java中没有直接修改字符串的方法,因此您可以采用任何方式进行操作。正如我所说:如果字符串非常大,请使用StringBuilder。 - Aaron Digulla
显示剩余2条评论

1
在Google上搜索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相同,但具有静态缓冲区)

这是我的结果:在 Windows Vista 和 jdk1.6.0_13 上使用提取的 rt.jar: ArrayTest 时间 = 2075 字节 = 2120336424 ArrayTest 时间 = 2044 字节 = 2120336424 ArrayTest_CustomBuffering 时间 = 1903 字节 = 2120336424 ArrayTest_CustomBuffering_StaticBuffer 时间 = 1872 字节 = 2120336424 DataInputByteAtATime 时间 = 2668 字节 = 2120336424 DataInputReadFully 时间 = 2028 字节 = 2120336424 MemoryMapped 时间 = 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);
     } 
 }

1
这个时间对我来说有点可疑。我不确定是否应该相信只有几秒钟长度的时间比较;JVM需要时间启动。我会使用更大的文件或更多的迭代。正如tofubeer指出的那样,您还需要在开始“真正”的计时之前包括至少一个额外迭代的循环,以预热磁盘缓存并让JVM的JIT完成其花式工作。 - Jason S
我在测试中将TofuBeer的“priming”副本作为第一次迭代保留了下来。文件已经从上一次运行中缓存。我正在XP框上重新运行测试,并得到类似的结果。当重用静态缓冲区与为每个文件创建新缓冲区时,速度降低让我感到困惑。也许这是底层JVM中的优化?不确定...我更愿意相信这是代码编写的问题。我认为我可能会在JAVA API的基础源代码中搜索,以查看NIO通道与FileInputStreams之间的情况。感谢您的帮助。 - jkaufmann

1

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

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

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

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

编辑:关于搜索和替换-只需使用{{link1:String的replaceAll函数}}。


0

任何常规方法的速度都会受到限制。我不确定你是否会从一个方法到另一个方法看到太大的差别。

我建议集中在能够使整个操作更快的业务技巧上。

例如,如果您读取了所有文件,并将它们存储在一个单独的文件中,并带有每个原始文件的时间戳,那么您可以在不实际打开它们的情况下检查文件是否发生了任何更改(换句话说,是一个简单的缓存)。

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

操作系统对于文件处理得非常好,如果这是批处理的一部分(无用户I/O),则可以使用类似以下方式的批处理文件将所有文件附加到一个大文件中,然后启动Java:

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

然后只需打开file.all文件(我不确定这样做会更快,但对于我刚才提到的条件来说,这可能是最快的方法)

我想我只是在说,通常解决速度问题的解决方案往往需要稍微扩大您的视野,并使用新参数完全重新思考解决方案。修改现有算法通常只会以可读性为代价获得轻微的速度增强。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接