在java中,FileInputStream中的read()方法为什么不抛出;不兼容类型:可能的有损转换“;?
我目前正在学习Java I/O,很难理解FileInputStream类的read()方法。我知道,根据Documanation,read()方法从流中读取数据的“byte”,并返回一个表示字节的整数(介于0和256之间),如果到达文件末尾,则返回-1 java中的字节的范围在-128和127之间,所以,为什么当我编辑xanadu.txt并添加ASCI符号“ƒ”(十进制值为131)时,java不会抛出一个错误来抱怨值131超出了字节(-128和127)定义的范围?当我尝试使用文字来测试时,我得到了两个不同的结果 以下工作:在java中,FileInputStream中的read()方法为什么不抛出;不兼容类型:可能的有损转换“;?,java,io,stream,byte,Java,Io,Stream,Byte,我目前正在学习Java I/O,很难理解FileInputStream类的read()方法。我知道,根据Documanation,read()方法从流中读取数据的“byte”,并返回一个表示字节的整数(介于0和256之间),如果到达文件末尾,则返回-1 java中的字节的范围在-128和127之间,所以,为什么当我编辑xanadu.txt并添加ASCI符号“ƒ”(十进制值为131)时,java不会抛出一个错误来抱怨值131超出了字节(-128和127)定义的范围?当我尝试使用文字来测试时,我得到
byte b = 120;
int c = b;
System.out.println((char)c);
Output: x
但这不起作用(即使添加到xanadu.txt中也可以):
我尝试使用byte显式强制转换:(这怎么可能?)
对于I/O流,我完全是新手,请有人帮助我理解它
编辑:原来我对类型转换的概念缺乏了解,特别是在理解“加宽”和“缩小”之间的区别方面。阅读更多关于这些概念的内容,有助于我理解为什么显式(也称为缩小)铸造有效
请允许我解释一下:请看第三个代码块,其中我显式地将文本“131”转换为字节类型。如果我们将文字131转换为32位有符号2的补码整数的二进制形式,我们将得到00000000 00000000 00000000 10000011,即32位或4字节。回想一下,Java数据类型“byte”只能保存8位有符号2的补码整数,因此131超出范围,因此我们得到错误“从int到byte的可能有损转换”。但是,当我们显式地将其转换为字节时,我们是在“截断”,或者正确的术语是将二进制“缩小”为8位整数。当我们这样做的时候,得到的二进制数是1000011,十进制值是-125。由于-125在-128和127范围内,所以字节在接受和存储它时没有问题。现在,当我尝试在int c中描述字节的值时,会发生隐式或“加宽”转换,其中8位10000011的二进制形式的-125转换为32位11111111111111111 10000011的二进制形式的等效-125。最后,system.out尝试输出(char)c的值,这是另一个显式或“缩小”强制转换,它试图从32位有符号压缩到16位无符号。铸造完成后,我们得到二进制形式的11111111 10000011。现在,当这个二进制文件被java转换成字符形式时,它返回テ.
最后,我可以说,它有助于将所有内容转换为二进制形式,并从中开始。但请确保您理解编码和
131的两个补码编码是:
2^7+2^1+2^0
^^^
sign bit
如果用于有符号类型的中没有溢出,131将无法装入有符号字节。最高位=符号位,在从字节转换为int时设置
Java编译器注意到131不能正确地放入一个字节,这导致了错误。我不知道131的值是从哪里来的,但就我而言,带HOOK(ƒ)的拉丁小写字母F不在原始ASCII字符集中,而是在扩展ASCII中,十进制值为159。看见它还以UTF-16(Java
char
s的编码方式)编码为十六进制192(十进制值402)
首先,确保您的文本文件以扩展ASCII编码,而不是UTF-8(最有可能的编码)。然后您可以使用FileInputStream
来读取该文件,您将获得159
请注意,159
超出了Javabyte
类型的范围。这很好,因为read
返回int
。但是,如果文本文件以UTF-8编码,则ƒ以2字节编码,因此read
将一次读取一个字节
第二个代码块不起作用,因为正如您所说,byte
从-128变为127,所以131显然不合适
您的第三个代码块将131强制转换为一个字节,这会导致溢出,值“回绕”为-125<代码>b
和c
都是-125。当您将其转换为char
时,它将变为65411,因为此转换需要先将整数填充到16位,然后将其视为无符号整数
当您使用
FileInputStream.read
而不是自己进行这些转换时,这一切都起作用的原因是read
实际上返回的是int
,而不是字节。只是它返回的
返回一个字节”,但它的实际返回类型是“代码> int .< /p>只是一个小注意:它不是一个“警告”,它是一个“错误”(代码不应该被成功编译),你是否考虑过检查文件的编码格式?字节不会自动成为字符。一个字符可以用许多字节编码。@akuzminykh,我的文件的编码是ANSI。“一个字符可以由许多字节编码”——那么这是否意味着ASCII扩展字符ƒ[带钩子的拉丁文小写字母f]被存储为多个字节,而不仅仅是一个字节?如果是这样,那就更有意义了。谢谢我使用ascii表列出。我使用记事本++,所以文本默认用ANSI编码。问题2:“请注意,159超出了Java字节类型的范围”-Java不应该抛出我在尝试使用文本时看到的错误吗“错误:不兼容类型:从int到byte的可能有损转换”?Q2:[…]但是,如果文本文件是用UTF-8编码的,那么ƒ是用2个字节编码的,所以read将一次读取一个字节”-我在这里感到困惑,正如您前面提到的,编码应该用ASCII而不是UTF-8?@PalonchiPismadonchi java不会抛出错误,因为总是在-1到255之间。这就是为什么我们说“<代码> Readint
根本不返回read
字节
byte b = (byte)131; int c = b; System.out.println((char)c); Output: テ
byte b = 131; // this is 8 bits type, but >8 bits value int c = b; // this is 32 bits type System.out.println((char)c); // this is 16 bits type Output: error: incompatible types: possible lossy conversion from int to byte byte b = 131;
2^7+2^1+2^0 ^^^ sign bit