【问题标题】:How can I read a file as unsigned bytes in Java?如何在 Java 中将文件读取为无符号字节?
【发布时间】:2011-02-28 15:41:28
【问题描述】:

如何在 Java 中将文件读取为字节?

需要注意的是,所有字节都需要为正数,即不能使用负数范围。

这可以在 Java 中实现吗?如果可以,如何实现?

我需要能够将文件的内容乘以一个常数。我假设我可以将字节读入 BigInteger 然后相乘,但是由于某些字节是负数,我最终会得到 12 13 15 -12 等并卡住。

【问题讨论】:

  • 对象DataInputStream提供readUnsignedByte()方法

标签: java file byte


【解决方案1】:

好吧,Java 没有无符号字节的概念……byte 类型始终是有符号的,其值从 -128 到 127(含)。但是,这将与使用无符号值的其他系统很好地互操作,例如,写入字节“255”的 C# 代码将生成一个文件,其中在 Java 中读取相同的值作为“-1”。小心点,你会没事的。

编辑:您可以使用位掩码非常轻松地将带符号的字节转换为具有 unsigned 值的int。例如:

byte b = -1; // Imagine this was read from the file
int i = b & 0xff;
System.out.println(i); // 255

使用int 完成所有算术运算,然后在需要再次写出时再转换回byte

您通常使用FileInputStreamFileChannel 从文件中读取二进制数据。

目前很难知道您还在寻找什么……如果您可以在问题中提供更多详细信息,我们或许可以为您提供更多帮助。

【讨论】:

  • 我需要能够将文件的内容乘以一个常数。我假设我可以将字节读入 BigInteger 然后相乘,但是由于某些字节是负数,我最终得到 12 13 15 -12 等并卡住了。
  • @tyr 您是单独将每个字节相乘,还是根据读取的几个字节构造BigInteger?如果是后者,我不明白为什么要将字节转换为无符号表示。
  • 我正在根据读取的字节构造一个 BigInteger。我正在转换它们,因为当我使用 BigInteger "12-1213" 提供方法时,会生成一个异常。 java.lang.NumberFormatException:非法嵌入减号
  • 读取的字节是大整数中的简单串联,一个字节紧挨着另一个。
  • @tyr Ahh,你传递了一个字符串。我以为你的意思是你将传递一个字节数组来构造BigInteger。对不起。
【解决方案2】:

有了unsigned API in Java 8,你就有了Byte.toUnsignedInt。这比手动投射和屏蔽要干净得多。

要将int 转换回byte,当然你只需要一个演员(byte)value

【讨论】:

    【解决方案3】:

    您在评论中写道(请将此类信息放在问题中 - 有一个编辑链接):

    我需要能够将文件的内容乘以一个常数。 我假设我可以将字节读入 BigInteger 然后 相乘,但是由于某些字节是负数,所以我要结束 增加 12 13 15 -12 等并卡住。

    如果您想将整个文件用作 BigInteger,请以 byte[] 的形式读取它,并将此数组(作为一个整体)提供给 BigInteger-constructor。

    /**
     * reads a file and converts the content to a BigInteger.
     * @param f the file name. The content is interpreted as
     *   big-endian base-256 number.
     * @param signed if true, interpret the file's content as two's complement
     *                  representation of a signed number.
     *               if false, interpret the file's content as a unsigned
     *                  (nonnegative) number.
     */
    public static BigInteger fileToBigInteger(File f, boolean signed)
        throws IOException
    {
        byte[] array = new byte[file.length()];
        InputStream in = new FileInputStream(file);
        int i = 0; int r;
        while((r = in.read(array, i, array.length - i) > 0) {
            i = i + r;
        }
        in.close();
        if(signed) {
            return new BigInteger(array);
        }
        else {
            return new BigInteger(1, array);
        }
    }
    

    然后您可以乘以您的 BigInteger 并将结果保存在一个新文件中(使用 toByteArray() 方法)。

    当然,这在很大程度上取决于文件的格式——我的方法假定文件包含toByteArray() 方法的结果,而不是其他格式。如果您有其他格式,请在您的问题中添加相关信息。

    “我需要能够将文件的内容乘以一个常数。” 似乎是一个非常可疑的目标——你真正想要做什么?

    【讨论】:

      【解决方案4】:

      如果在内部使用更大的整数类型不成问题,只需采用简单的解决方案,在所有整数相乘之前将它们加到 128。你得到的不是 -128 到 127,而是 0 到 255。加法并不困难;)

      另外,请记住 Java 中的算术和位运算符只返回整数,所以:

      byte a = 0;
      byte b = 1;
      
      byte c = a | b;
      

      会给出一个编译时错误,因为 | b 返回一个整数。你必须这样做

      byte c = (byte) a | b;
      

      所以我建议在所有数字相乘之前只加上 128。

      【讨论】:

      • 假设他想从二进制补码转换为无符号,这是行不通的。例如 -1 + 128 等于 127 not 255,应该是这样。此外,转换回一个字节会改变一个字节范围之外的任何值。
      【解决方案5】:

      一些测试表明,这会从文件中一一返回 [0…255] 范围内的无符号字节值:

      Reader bytestream = new BufferedReader(new InputStreamReader(
              new FileInputStream(inputFileName), "ISO-8859-1"));
      int unsignedByte;
      while((unsignedByte = bytestream.read()) != -1){
          // do work
      }
      

      它似乎适用于该范围内的所有字节,包括那些在 ISO 8859-1 中未定义字符的字节。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-18
        相关资源
        最近更新 更多