Java 使用ObjectOutputStream时估计磁盘上的文件大小

Java 使用ObjectOutputStream时估计磁盘上的文件大小,java,size,fileoutputstream,objectoutputstream,Java,Size,Fileoutputstream,Objectoutputstream,我正在尝试将空间数据从表写入文件。但在写入磁盘之前,我需要知道磁盘上数据的确切大小。例如,假设我正在使用以下代码写入磁盘: FileOutputStream fos = new FileOutputStream("t.tmp",false); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeInt(gid); oos.writeUTF(fullname); oos.writeIn

我正在尝试将空间数据从表写入文件。但在写入磁盘之前,我需要知道磁盘上数据的确切大小。例如,假设我正在使用以下代码写入磁盘:

    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的空间

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


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

如果您不介意浪费一些内存,您可以先将其全部写入
ByteArrayOutputStream
,然后获取大小

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();
我正在尝试将空间数据从表写入文件。但在写入磁盘之前,我需要知道磁盘上数据的确切大小

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

取而代之的是,只需使用一个。它提供与您所需相同的功能:

数据输出流允许应用程序以可移植的方式将原始Java数据类型写入输出流。然后,应用程序可以使用数据输入流将数据读回

这里不会有任何意外(前提是您知道UTF编码字符串将结束多少字节),并且您可以通过算术计算出确切的文件大小


(如果您处理的字符串不只是一个字符一个字节,您可以先使用字符集编码器将字符串呈现到字节数组中)。

您真的需要ObjectOutputStream吗?您是否使用
writeObject()
?或者您的示例代码是否像您得到的那样复杂?看来你最好还是用一个新的。(一个
ObjectOutputStream
写入流头信息并跟踪对已经写入的对象的引用,这样它就可以简单地编写一个引用等,所有这些都会妨碍您预先计算大小。)另外,您是否可以从性能问题的角度,详细介绍在写入字节后使用文件系统时发现的性能问题。我的表中有40GB的数据,其中许多是空间数据。我对表进行分区的方式是,每个文件中存储的数据的总大小小于某个值(max_file_size)。在第一轮中,我计算表中每一行在磁盘上的大小,在下一轮中,我将它们相加,使之可以放入一个总文件大小小于max_file_size的文件中。因此,写入每个文件,然后测量磁盘上的实际文件大小不是一个选项。就ObjectOutputStream的使用而言,我不确定这是否是写入磁盘的最佳方式。除了一个长度可变的字节数组几何体之外,我还有几个字段要输入varchar(x)。我认为ObjectOutputStream是读取/写入文件的最简单方法。事实上,到目前为止效果还不错。唯一的问题是,我必须提前根据数据值计算磁盘上的大小。有什么建议吗?
ObjectOutputStream
的用处在于它能够自动序列化复杂的对象图。然而,这似乎不是您正在做的事情,因此我建议您省去
ObjectOutputStream
,只需使用。
DataOutputStream
不会自动执行任何操作,因此您将能够执行预期的大小计算。注意
DataOutputStream.writeUTF()的Javadoc,因为它写入2字节的长度数据,然后是String.great。如果我想计算一行数据的大小,这很好。我为每一行数据计算这个值,并将其存储在表中block_size列下。然后我选择了太多的行,以至于它们的累积块大小小于某个值。问题是两行的block_size值之和大于写入磁盘的两行的文件大小。关于如何解决这一部分有什么想法吗?@reza如果你需要准确,你必须先在内存中序列化整个数据结构(或到一个临时文件)。Java序列化将在一定程度上删除重复的对象和字符串,因此你不能假设数据加倍将占用两倍的空间。谢谢,我最终使用了DataOutputStream。这样,我计算的大小与磁盘上的文件大小完全相同。谢谢你的建议。非常感谢。这就解决了问题。似乎我需要刷新Java流上的内存。你推荐一些关于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();