DataOutputStream如何将基本类型的值转换为字节序列?

时间:2017-11-22 11:32:18

标签: java

DataOutputStream具有转换基元值的方法     键入一个字节序列,然后将其写入底层     流。

  1. 我想知道转换是如何完成的?转换不是 更改存储在内存中的数据,但重新解释a的数据 原始类型作为字节序列?
  2. 如何使用OutputStream模拟转化(例如, FileOutputStream),了解DataOutputStream目的?这是我的尝试:

    try(FileOutputStream fout = new FileOutputStream("myfile")){
        Random random = new Random();
        for (int i=0; i<100; i++){
            int tmp = random.nextInt();
            System.out.println(tmp);
            fout.write((byte[])tmp);  // error: incompatible types: int cannot be converted to byte[]
        }
    } catch (IOException e){
        System.err.println(e);
    }
    

    但我收到的是(byte[])tmp

    error: incompatible types: int cannot be converted to byte[]
    

    为什么我无法将int投射到byte[]

    我该如何模拟转换?

    如果我有一个int数组,我可以使用FileOutputStream的单个写方法模拟转换,而不是每个元素的元素调用一次write方法吗? 感谢。

2 个答案:

答案 0 :(得分:0)

  

我想知道转换是如何完成的?

最简单的方法是阅读代码或Javadoc。

/**
 * Writes an <code>int</code> to the underlying output stream as four
 * bytes, high byte first. If no exception is thrown, the counter
 * <code>written</code> is incremented by <code>4</code>.
 *
 * @param      v   an <code>int</code> to be written.
 * @exception  IOException  if an I/O error occurs.
 * @see        java.io.FilterOutputStream#out
 */
public final void writeInt(int v) throws IOException {
    out.write((v >>> 24) & 0xFF);
    out.write((v >>> 16) & 0xFF);
    out.write((v >>>  8) & 0xFF);
    out.write((v >>>  0) & 0xFF);
    incCount(4);
}
  

转换是否不会更改存储在内存中的数据,而是将基本类型的数据重新解释为字节序列?

没有

  

那么我该如何模拟转换?

你不能Java不玩那些技巧。

注意:您可以使用Unsafe类执行此操作,但除非没有其他选择,否则应避免使用它,因为它不安全

  

你在哪里找到“代码”?

您可以通过点击课程或搜索课程在IDE中找到它,也可以谷歌查看来源。

  

为什么我不能将int转换为byte []

Java中没有这样做的定义。例如它应该是小端还是大端?请注意byte[]是一个对象。

  

为什么代码并不意味着“转换不会改变存储在内存中的数据,而是将原始类型的数据重新解释为字节序列?”

没有Java语言可以做到这一点。有一些低级库工具可以执行此操作,但这些工具具有非常具体的用例。

答案 1 :(得分:0)

  

如何从int转换为byte[]

这是一段将进行转换的代码。

对于后来的读者:向下滚动以查看将整数数组转换为字节数组的示例。

我将在下面解释这段代码。

static byte[] convertIntToByteArray(int x)
{
    // This assumes that int is 32-bit and has a size of 4 bytes
    byte[] b = new byte[4];
    b[i] = ((x >>> 24) & 0xFF);
    b[i] = ((x >>> 16) & 0xFF);
    b[i] = ((x >>>  8) & 0xFF);
    b[i] = ((x >>>  0) & 0xFF);
    return b;
}

此代码是将int拆分为byte[]的低效但兼容的方式。它手动使用位掩码(如DataOutputStream)来操作每个字节。

但是,理论上你是正确的。 int表示为内存中的单个字节,但软件会为您抽象。

注意:您也可以使用Unsafe类来执行此操作。但是,它并不完全安全(用讽刺阅读),并且它很容易受到Java内部布局和平台差异的影响。此外,甲骨文一直试图杀死Unsafe一段时间。因此,上面的方法是一种较慢但非常兼容的处理方法,如果你不试图编写模拟器,那么你应该能够摆脱性能损失。

TL; DR

无需模拟转换。只需使用DataOutputStream

但是,如果您真的想要模拟它,可以创建一个byte[]数组并手动将ints放入其中,然后将其传递给ByteArrayOutputStream,如下所示。这基本上复制了Java中的现有功能,我建议使用内置函数,因为它们几乎可以保证比您的更优化。我从上面的彼得的答案中借用了一些代码。

byte[] b = new byte[Integer.SIZE*4]; // large enough to hold 4 int vars (each int is guaranteed to be Integer.SIZE bytes)
int[] a = new int[4];
for(int i = 0, j = 0; i < b.length; i+=Integer.SIZE, j++)
{
    b[i] = ((a[j] >>> 24) & 0xFF);
    b[i] = ((a[j] >>> 16) & 0xFF);
    b[i] = ((a[j] >>>  8) & 0xFF);
    b[i] = ((a[j] >>>  0) & 0xFF);
}
FileOutputStream fo = new FileOutputStream("[your filename here]"); // WARNING: In real code, you need to handle the FileNotFoundException
fo.write(b);
fo.close();