2012-06-29 73 views
1

我正在为我的游戏制作高分实现。这里有我想要做的: 我有对象分数,其中包含字符串名称和整数分数。 现在:文件编写器Java;如何覆盖

  • 如果名称是不是已经在该文件中,添加它
  • 如果名称是文件,一个空间后取字符串并将其转换为整数,所以我得到的分数。

现在,如果分数比实际更好,我必须在文件上覆盖它... 这是我的问题..我可以这样做吗?我怎样才能在文件的某个点上准确地写入另一个字符串?

+0

你真的需要在同一个地方覆盖文本,还是只需要记录新的高分?例如使用属性可能是最简单的,但这不会保留条目的顺序。 –

回答

-1

只是一个想法,文件存储名称和分数的任何具体原因?

似乎是一个Map<String, Integer>将有助于你更好......

+1

显然,高分需要持久。 –

+0

对我而言没有用 –

4

通常它被认为过于繁琐,以取代在文本文件中的文本对于这种要求,因此通常的方式做到这一点仅仅是阅读整个文件,进行替换并写入整个文件的新版本。如果您有大量数据,则可以使用数据库或NoSQL解决方案。

P.S.考虑使用序列化,它可以让事情变得更容易。

+0

我也会推荐在你的用例中使用序列化。让Java平台通过使用可序列化的集合实现并使您的包含对象可序列化来为您完成繁重任务。这样你所需要做的就是将你的集合写入一个ObjectOutputStream并完成它。 – Kallja

+0

@Jarkko对象序列化不像“属性”文件,文本或数据库那样健壮(跨版本)。 –

+0

@AndrewThompson授予。这很简单,但我经常在数据丢失不是关键因素的情况下使用它。显然,SQLite(或任何其他的数据库)数据库也将是这里描述的使用的合适方法。 – Kallja

1

我有包含字符串名称和整数分数的对象得分。

改为使用Properties文件。它提供了一个简单的界面来加载保存文件,获取键(名称)和设置或检索值(分数)。 String值存储,但它们可以轻松地转换为/从整数。

1

我同意这最好通过完全重新序列化整个数据库来完成。在现代计算机上,每个磁盘可以推送30MB/s用于线性写入(如果有足够的缓存,则可以更多)。如果你处理的数据超过30MB,你真的需要一个数据库(HSQLDB,DerbyDB,BerkleyDB)是简单的数据库。或者一路去postgres/mysql。

但是,要覆盖现有文件的固定大小部分的方式(或者更确切地说,效仿这样的方式),是使用:

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

注意使用writeInt代替raf.write的(Integer.toHexString(newScore).getBytes()),因为你确实需要在大小上进行修正。

现在,如果文本文件是内在的ascii(例如人类将读取文件),因此该值不能是二进制的。也许你可以保留它的HexString(因为这将是固定的大小),或你可以填零十进制字符串:

但绝对肯定不能做的是将字符串增长1个字节。 所以:

bob 15 
joe 7 
nina 981 

不能有乔的分数换成10,除非你已经填补了一堆的空间。

如果这是您的数据文件,那么您绝对必须重写整个文件(即使您编写额外的代码以仅从更改点重写 - 统计上该文件将占文件的50%因而不值得打扰其他

一两件事 - 如果你不重写,你缩短了文件的风险。对于您需要调用 raf.setLength(0); 写的第一个字节之前。否则,你会在新文件末尾看到幻影文字

0
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)); 
    } 
} 

我可能会ra使用DB或二进制映射文件..每个字段含有8B,4B指向用户名位置,4B代表分数。但是,这允许用户可读的数据文件,同时更新速度比重写属性文件更快。

查看LevelDB - 这个星球上嵌入式系统最快的DB。 :)它的主要作用就是每秒更新数千次/百万次,而不需要在多GB文件中随机更新6个字节的rand-seek-rewrite成本。