将文件加载到内存(Java)?
我有一个60 MB的文本文件,我的程序通过它搜索特定的ID并提取一些相关的文本。我必须对200多个ID重复这个过程。最初,我使用循环遍历文件的行,查找ID,然后提取相关文本,但这需要花费很长的时间(~2分钟)。所以,现在我想把整个文件加载到内存中,然后从内存中搜索我的ID和相关文本;我想这应该比访问硬盘快200多次。因此,我编写了以下代码将文件加载到内存中:将文件加载到内存(Java)?,java,file,optimization,io,Java,File,Optimization,Io,我有一个60 MB的文本文件,我的程序通过它搜索特定的ID并提取一些相关的文本。我必须对200多个ID重复这个过程。最初,我使用循环遍历文件的行,查找ID,然后提取相关文本,但这需要花费很长的时间(~2分钟)。所以,现在我想把整个文件加载到内存中,然后从内存中搜索我的ID和相关文本;我想这应该比访问硬盘快200多次。因此,我编写了以下代码将文件加载到内存中: public String createLocalFile(String path) { String text = "";
public String createLocalFile(String path)
{
String text = "";
try
{
FileReader fileReader = new FileReader( path );
BufferedReader reader = new BufferedReader( fileReader );
String currentLine = "";
while( (currentLine = reader.readLine() ) != null )
{
text += currentLine;
System.out.println( currentLine );
}
}
catch(IOException ex)
{
System.out.println(ex.getMessage());
}
return text;
}
不幸的是,将文件文本保存到字符串变量中需要非常长的时间。如何更快地加载文件?还是有更好的方法来完成同样的任务?谢谢你的帮助
编辑:这里是指向文件https://github.com/MVZSEQ/denovoTranscriptomeMarkerDevelopment/blob/master/Homo_sapiens.GRCh38.pep.all.fa
典型的线条如下所示:
>ENSP00000471873 pep:putative chromosome:GRCh38:19:49496434:49499689:1 gene:ENSG00000142534 transcript:ENST00000594493 gene_biotype:protein_coding transcript_biotype:protein_coding\
MKMQRTIVIRRDYLHYIRKYNRFEKRHKNMSVHLSPCFRDVQIGDIVTVGECRPLSKTVR\
FNVLKVTKAAGTKKQFQKF\
其中ENSP0000471873
是ID,我要提取的文本是
MKMQRTIVIRRDYLHYIRKYNRFEKRHKNMSVHLSPCFRDVQIGDIVTVGECRPLSKTVR\
FNVLKVTKAAGTKKQFQKF\
如果文件包含一组记录,则您可以
1.创建一个具有id和文本内容属性的类。
2.从文件中读取每条记录,并从中创建一个对象,然后将其添加到HashMap。
3。使用HashMap按与大多数其他注释一致的ID检索对象。60MB对于今天的记忆来说并不是太大。但时间被浪费的地方几乎肯定是在每一行后面加上“+=”一个越来越庞大的字符串。排成一行
更好的是,在阅读时将ID文本和“相关文本”分开,以使后面的ID搜索更快。哈希表是理想的。您的思路肯定是正确的,您应该将其读入内存,并通过某种映射来访问它。这将消除很多瓶颈,即磁盘I/O和访问时间(内存要快得多) 我建议将数据读入
HashMap
,ID为键,文本为值
尝试以下方法:
public Map<Integer, String> getIdMap(final String pathToFile) throws IOException {
// we'll use this later to store our mappings
final Map<Integer, String> map = new HashMap<Integer, String>();
// read the file into a String
final String rawFileContents = new String(Files.readAllBytes(Paths.get(pathToFile)));
// assumes each line is an ID + value
final String[] fileLines = rawFileContents.split(System.getProperty("line.separator"));
// iterate over every line, and create a mapping for the ID to Value
for (final String line : fileLines) {
Integer id = null;
try {
// assumes the id is part 1 of a 2 part line in CSV "," format
id = Integer.parseInt(line.split(",")[0]);
} catch (NumberFormatException e) {
e.printStackTrace();
}
// assumes the value is part 2 of a 2 part line in CSV "," format
final String value = line.split(",")[1];
// put the pair into our map
map.put(id, value);
}
return map;
}
此示例代码未经测试,并对文件格式进行了一些假设,即每行一个ID和值,并且它们的ID和值是逗号分隔的(CSV)。当然,如果您的数据结构有点不同,只需根据口味调整即可
已更新以匹配您的文件描述:
public Map<String, String> getIdMap(final String pathToFile) throws IOException {
// we'll use this later to store our mappings
final Map<String, String> map = new HashMap<String, String>();
// read the file into a String
final String rawFileContents = new String(Files.readAllBytes(Paths.get(pathToFile)));
// assumes each line is an ID + value
final String[] fileLines = rawFileContents.split(System.getProperty("line.separator"));
// iterate over every line, and create a mapping for the ID to Value
for (final String line : fileLines) {
// get the id and remove the leading '>' symbol
final String id = line.split(" ")[0].replace(">", "").trim();
// use the key 'transcript_biotype:' to get the 'IG_D_gene' value
final String value = line.split("transcript_biotype:")[1].trim();
// put the pair into our map
map.put(id, value);
}
return map;
}
publicmap getIdMap(最终字符串pathToFile)引发IOException{
//稍后我们将使用它来存储映射
final Map=new HashMap();
//将文件读入字符串
最终字符串rawFileContents=新字符串(Files.readAllBytes(path.get(pathToFile));
//假设每行都是ID+值
最终字符串[]fileLines=rawFileContents.split(System.getProperty(“line.separator”);
//迭代每一行,并创建ID到值的映射
for(最后一行字符串:文件行){
//获取id并删除前导“>”符号
最终字符串id=line.split(“”[0]。替换(“>”,“”)。trim();
//使用键“transcript_biotype:”获取“IG_D_基因”值
最终字符串值=line.split(“转录本生物类型:”)[1].trim();
//把这一对放到我们的地图上
map.put(id,value);
}
返回图;
}
假设您的虚拟机有足够的堆分配给它,您可以将原始文件加载到内存中,如下所示:
public byte[] loadFile(File f) throws IOException {
long size = f.length();
InputStream source;
byte[] bytes;
int nread;
int next;
if (size > Integer.MAX_VALUE) {
throw new IllegalArgumentException("file to long");
}
bytes = new byte[(int)size];
source = new FileInputStream(f);
for (next = 0; next < bytes.length; next += nread) {
nread = source.read(bytes, next, bytes.length - next);
if (nread < 0) {
throw new FileTruncatedWhileReadingItException();
// or whatever ...
}
}
if (source.read() != -1) {
throw new FileExtendedWhileReadingItException();
// or whatever ...
}
return bytes;
}
public byte[]加载文件(文件f)引发IOException{
长尺寸=f.长度();
输入流源;
字节[]字节;
国际nread;
int-next;
如果(大小>整数最大值){
抛出新的IllegalArgumentException(“文件变长”);
}
字节=新字节[(int)大小];
source=新文件输入流(f);
for(next=0;next
然后,通过在内存中创建ByteArrayInputStream
,您可以处理该副本,而不是从磁盘读取—您应该能够相对轻松地将其插入到现有代码中
可能还有其他方法可以进一步优化。例如,如果处理数据必然涉及将其解码为字符,那么您可以通过使用读取器
读入字符[]
而不是输入流
读入字节[]
来缓存解码结果,然后以类似的方式进行。但是请注意,以char
格式存储ASCII数据所占用的空间是以byte
格式存储ASCII数据所占用空间的两倍
如果数据是合适的,那么对一些更复杂的数据结构执行完整的解析可能会很有用,例如
映射
,这可能会使后续的查找非常快。当然,代价是更多的内存使用。我认为你的问题来自文本中添加字符串。您应该改用StringBuffer
。我还建议您使用扫描仪
类而不是文件阅读器
:
public String createLocalFile(String path)
{
StringBuffer text = new StringBuffer();
try
{
Scanner sc = new Scanner( new File(path) );
while( sc.hasNext() )
{
String currentLine = sc.nextLine();
text.append(currentLine);
System.out.println( currentLine );
}
}
catch(IOException ex)
{
System.out.println(ex.getMessage());
}
return text.toString();
}
这应该快得多。您使用的是FASTA文件。尝试一下……有很多库可以解析和处理这些类型的文件。无论您在做什么,都很可能已经完成了……您没有访问硬盘200次。没有一个健全的操作系统是这样工作的。将文件放入某种合理的结构中,例如字符串数组。如果您试图在文本文件中维护某种类型的“数据库”,可能您应该使用数据库您可以使用
StringBuilder
而不是字符串串联(可能是编译器)
public String createLocalFile(String path)
{
StringBuffer text = new StringBuffer();
try
{
Scanner sc = new Scanner( new File(path) );
while( sc.hasNext() )
{
String currentLine = sc.nextLine();
text.append(currentLine);
System.out.println( currentLine );
}
}
catch(IOException ex)
{
System.out.println(ex.getMessage());
}
return text.toString();
}