简体   繁体   English

文件编写Java; 如何改写

[英]File Writer Java ; how to overwrite

i'm making an Highscore implementation for my game. 我正在为我的游戏制作Highscore实现。 Here there's what i want to do: I have object Score which contains String Name and Integer score. 这是我想做的:我有对象Score,其中包含String Name和Integer score。 Now : 现在:

  • if Name isn't already in the file, add it 如果文件中还没有名称,请添加它
  • if Name is on the file, after a space take the String and convert into integer, so i got the score. 如果Name在文件上,请在空格后加上String并将其转换为整数,以便得到分数。

Now, if score is better than the actual, i have to OVERWRITE it on the file... and here's my problem..i can i do that? 现在,如果分数比实际要好,我必须在文件上覆盖它……这是我的问题..我可以这样做吗? how can i write exactly a string over another in a certain point of the file? 如何在文件的特定位置上在另一个字符串上确切地写一个字符串?

Generally it's considered too fiddly to replace text in text files for this kind of requirement, so the usual way to do it is just to read in the whole file, make the replacement and write a new version of the whole file. 通常,对于这种要求,替换文本文件中的文本被认为太过分了,因此通常的做法是读取整个文件,进行替换并编写整个文件的新版本。 If you have large amounts of data you would use a database or a NoSQL solution instead. 如果您有大量数据,则可以使用数据库或NoSQL解决方案。

PS consider using serialization, it can make things easier. PS考虑使用序列化,它可以使事情变得容易。

I have object Score which contains String Name and Integer score. 我有包含字符串名称和整数得分的对象Score。

Use a Properties file for this instead. 为此,请使用Properties文件。 It provides an easy interface to load & save the file, get the keys (Name) and set or retrieve values (Score). 它提供了一个简单的界面来加载和保存文件,获取键(名称)以及设置或检索值(分数)。 String values are stored, but they can be converted to/from integer easily. String值已存储,但可以轻松将其转换为整数。

I concur that this is best done by fully re-serializing the entire database. 我同意最好通过完全重新序列化整个数据库来完成此操作。 On modern computers, you can push 30MB/s per disk for linear writes (more if there's sufficient cache). 在现代计算机上,每个磁盘可以推动30MB / s的速度进行线性写入(如果有足够的缓存,则可以增加更多速度)。 And if you're dealing with more than 30MB of data, you REALLY need a DB (HSQLDB, DerbyDB, BerkleyDB) are trivial DBs. 而且,如果您要处理超过30MB的数据,则确实需要一个数据库(HSQLDB,DerbyDB,BerkleyDB)是不重要的数据库。 Or go all the way to postgres/mysql. 或一直到postgres / mysql。

However, the way to overwrite a FIXED sized section of an existing file (or rather, the way to emulate doing so), is to use: 但是,覆盖现有文件的FIXED大小的部分的方法(或更确切地说,是模仿这样做的方法)是使用:

RandomAccessFile raf = new RandomAccessFile(fileName, "rw");
try {
  raf.seek(position);
  raf.writeInt(newScore);
  raf.close();
} finally { raf.close(); }

Note using the writeInt instead of raf.write(Integer.toHexString(newScore).getBytes()), because you really really need that to be fixed in size. 请注意,使用writeInt而不是raf.write(Integer.toHexString(newScore).getBytes()),因为您确实需要固定大小。

Now if the text file is intrinsicly ascii (eg humans will read the file), and thus the value can't be binary.. Perhaps you could keep it HexString (because that will be fixed in size), or you could a zero-padded decimal string: 现在,如果文本文件本质上是ascii(例如,人类将读取该文件),那么该值就不能为二进制。。也许您可以将其保留为HexString(因为它将固定大小),或者您可以将其设置为零,填充十进制字符串:

But what you absoluately positively can not do is grow the string by 1 byte. 但是您绝对不能做的是将字符串增加1个字节。 So: 所以:

bob 15
joe 7
nina 981

Can't have joe's score replaced with 10, UNLESS you've padded a bunch of spaces. 除非您在空白处填充空格,否则无法用10代替joe的分数。

If this is your data-file, then you will absolutely have to rewrite the whole file (even if you write the extra code to only rewrite from the point of change on - statistically that'll be 50% of the file and thus not worth bothering. 如果这是您的数据文件,那么您将绝对必须重写整个文件(即使您编写了仅从更改的角度重写的额外代码-统计上也就是文件的50%,因此不值得烦。

One other thing - if you do rewrite, you have the risk of shortening the file.. For that you need to call raf.setLength(0); 另一件事-如果您重写,则有缩短文件的风险。为此,您需要调用raf.setLength(0);。 before writing the first byte.. Otherwise, you'll see phantom text beyond the end of your new file. 在写入第一个字节之前。否则,您将在新文件末尾看到幻影文本。

final Map<String,Long> symbol2Position = new ConcurrentHashMap<>();
final Map<String,Integer> symbol2Score    = new ConcurrentHashMap<>();
final String fileName;
final RandomAccessFile raf;
// ... skipped code
void storeFull() {
     raf.position(0);
     raf.setLength(0);
     for (Map.Entry<String,Long> e : symbol2Position.entrySet()) {

        raf.writeUTF8(e.getKey());
        raf.write(',');
        symbol2Score.put(e.getKey(), raf.position());
        raf.writeUTF8(String.format("%06d",e.getValue()));
        raf.write('\n');
     }
}
void updateScore(String key, int newScore) {
    if (symbol2Score.containsKey(key)) {
       symbol2Score.put(key, newScore);
       raf.position(symbol2Position.get(key));
       raf.writeString(String.format("%06d", newScore));
    } else {
       symbol2Score.put(key, newScore); 
       long fileLen = raf.length();
       symbol2Position.put(key, fileLen);
       raf.position(fileLen);
       raf.writeString(String.format("%06d", newScore));
    }
}

I'd probably rather use a DB or binary map file.. meaning file with 8B per field, 4B pointing to user-name position, and 4B representing score. 我可能宁愿使用DB或二进制映射文件..意思是每个字段有8B,指向用户名位置的4B和代表得分的4B的文件。 But this allows for a human readable data-file, while making updates faster than just rewriting the property file. 但这允许人类可读的数据文件,同时使更新比仅重写属性文件快。

Check out LevelDB - fastest damn DB on the planet for embedded systems. 查看LevelDB-嵌入式系统上该死的最快的DB。 :) Main thing it has over the above, is thousands / millions of updates per second without the rand-seek-rewrite cost of updating 6 bytes randomly across a multi-GB file. :)上面的主要内容是每秒数千次/数百万次更新,而无需花费rand-seek-rewrite的代价来跨多个GB文件随机更新6个字节。

Just a thought, any specific reason for the file storage of names and scores ? 只是想一下,文件名称和分数存储的任何特定原因?

Seems like a Map<String, Integer> would serve you much better... 似乎Map<String, Integer>会为您提供更好的服务...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM