2012-06-26 45 views
3

我想将我的空间数据从表中写入文件。但在写入磁盘之前,我需要知道磁盘上数据的确切大小。作为一个例子,让我们说,我现在用的是下面的代码写入到磁盘:当使用ObjectOutputStream时估计磁盘上的文件大小

FileOutputStream fos = new FileOutputStream("t.tmp",false); 
    ObjectOutputStream oos = new ObjectOutputStream(fos); 
    oos.writeInt(gid); 
    oos.writeUTF(fullname); 
    oos.writeInt(d.shape.length); 
    oos.write(d.shape); 

    oos.close(); 
    fos.close(); 

我想对磁盘文件的大小等于:

size= 4B {for gid, int} + fullname.getBytes.length() {string} + 4B {d.shape.length, int} + d.shape.length 

但实际上,这是非常与磁盘上的实际文件大小不同。

我也注意到,即使创建使用ObjectOutputStream一个空文件导致磁盘空间4B。

有关如何计算磁盘上文件大小的任何帮助?

(我不能将数据写入到磁盘,然后读出真实大小,这会降低性能。相反,我需要根据存储在内存中的数据值来计算磁盘上的数据的大小。)

+0

你真的需要一个* Object * OutputStream吗?你使用'writeObject()'?或者,您的示例代码像您所获得的那样复杂?看起来你最好使用[DataOutputStream](http://docs.oracle.com/javase/6/docs/api/java/io/DataOutputStream.html)。 (一个'ObjectOutputStream'写入流标题信息并跟踪已写入对象的引用,以便它可以简单地编写引用等等 - 所有这些都会妨碍你预先计算大小的努力。) –

+0

另外 - 您可以扩展您在写入字节后使用文件系统感知的性能问题吗?在性能问题方面 –

+0

。我的表格中有40GB的数据,其中很多都是空间数据。我正在对表格进行分区,使每个文件中存储的数据总大小小于某个值(max_file_size)。在第一轮中,我计算了我的表的每一行的磁盘大小,并在下一轮中,我总结了很多可以适用于文件总大小小于max_file_size的文件。因此,写入每个文件然后测量磁盘上的实际文件大小不是一种选择。 – reza

回答

1

假设你不介意浪费一些内存,你可以先把它全写出去,然后得到大小。

ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
ObjectOutputStream oos = new ObjectOutputStream(boas); 
oos.writeInt(gid); 
oos.writeUTF(fullname); 
oos.writeInt(d.shape.length); 
oos.write(d.shape); 

oos.close(); 
boas.close(); 
int size = boas.size(); 
+0

太棒了。这工作正常,如果我想计算一行数据的大小。我正在计算每行数据并将其存储在我的表的block_size列下。然后,我选择很多行,其累积block_size小于某个值。问题是两行的block_size值的总和大于写入磁盘的两行的文件大小。有关如何解决这部分的任何想法? – reza

+0

@reza如果你需要它是准确的,你必须首先在内存中序列化整个数据结构(或者到一个临时文件)Java序列化将删除重复的对象和字符串到一定程度,所以你不能假设数据会增加一倍两倍的空间。 –

+0

谢谢,我结束了使用DataOutputStream。这样,我的计算大小就像磁盘上的文件大小一样。感谢您的建议。 – reza

2

我试图从表中写我的空间数据文件。但在写入磁盘之前,我需要知道磁盘上数据的确切大小。

您不应该使用ObjectOutputStream。一个ObjectOutputStream可以为你自动序列化一个复杂的物体图形 - 但这似乎不是你的要求之一。作为该序列化的一部分,ObjectOutputStream会写入一些流头信息(这是您在开始时发现的4个字节),并且还会跟踪先前写入的对象,以便它可以写入特殊标记值而不是再次写出整个对象。

取而代之,只需使用DataOutputStream即可。它提供了您想要的相同功能:

数据输出流允许应用程序以便携方式将原始Java数据类型写入输出流。然后应用程序可以使用数据输入流中读取数据回。

FileOutputStream fos = new FileOutputStream("t.tmp",false); 
DataOutputStream dos = new DataOutputStream(fos); 
dos.writeInt(gid);     // write 4 bytes 
dos.writeUTF(fullname);   // write 2 bytes of length, then variable length string (UTF encoded) 
dos.writeInt(d.shape.length);  // write 4 bytes 
dos.write(d.shape);    // write a variable length byte array 

dos.close(); 
fos.close(); 

不会有什么惊喜在这里(前提是你知道有多少字节的UTF编码字符串将结束),和你可以做算术来计算确切的文件大小。

(如果你处理字符串不只是等同于一个字符一个字节,你可以渲染字符串首先使用的字符集编码的字节数组)。

+0

非常感谢。这解决了这个问题。似乎我需要在Java流上刷新我的记忆。你推荐任何有关Java流的教程吗? – reza

+0

@reza:不,对不起 - 我只是谷歌... ... –