javaフローでファイルタイプを判断する
8542 ワード
原文:
http://rainsilence.iteye.com/blog/842338
java中byte変換intの場合、なぜ0 xffと演算するのですか?
この問題を分析する前に、下記のコードを見てください。
b[i]&0 xFFは演算してもなおintなのに、なぜ0 xFFと演算するのですか?直接Integer.toHexString(b[i]);byteをintに強くしてはいけませんか?答えはだめです
その理由は:
1.byteのサイズは8 bittsでintのサイズは32 bittsです。
2.javaのバイナリは補数形式を採用しています。
ここでまずコンピューターの基礎理論を復習します。
byteはバイトで保存されています。8ビットがあります。すなわち、8ビットが0、1です。
8位の最初のビットは符号ビットであり、
つまり0000 0001は数字の1です。
1000 0000は-1を表しています。
ですから、正数が一番大きいのは0111 1111、つまり127です。
負の数は最大1111 1111、つまり数字-128です。
上に述べたのはバイナリコードですが、javaでは補数コードという形をとっています。以下は補数コードとは何かを紹介します。
1、逆コード:
一つの数が正しければ、その逆コードはもとのコードと同じです。
一つの数が負であれば、記号のビットは1であり、残りの各ビットは原コードに対して逆である。
2、補数:オーバーフローを利用して、減算を加算に変えることができます。
10進数に対しては、9から5を得ると減算できます。
9-4=5 4+6=10なので、6を4の補数にしてもいいです。
加算に書き換える:
9+6=15(上位1、つまりマイナス10)を5.
16進数については、cから5まで減算ができます。
c-7=5 7+9=16は9を7の補数とするからです。
加算に書き換える:
c+9=15(上位1、つまりマイナス16)を5.
コンピュータの中で、もし私達は1バイトで1つの数を表すならば、1バイトは8ビットあって、8ビットを上回って1に進んで、メモリの中で情況は(10000000000)で、進数1は捨てられます。
(1つの数が正であれば、その原コード、逆コード、補数は同じである)
⑵一つの数は負で、一つの記号のビットは1で、残りの各ビットは原コードに対して逆を取り、全体の数は1を加算する。
-1の原コードは 100000 1
-1の逆コードは 11111110
+ 1
-1の補数は 11111111
0の原コードは 0000000
0の逆コードは 11111111(正のゼロと負のゼロの逆符号は同じ)
+1
0の補数は 10000000000(打抜きの1、プラスゼロとマイナスゼロの補数は同じです。)
Integer.toHexStringのパラメータはintであり、&0 xffを行わないと、1 byteがintに変換される場合、intは32ビットであるのに対し、byteは8ビットしかない場合は補足されます。
たとえば、補数11111111の10進数が−1に変換されてintに変換されると11111111111111111111111111111111111111111111の多くの1になります。つまり0 xffffffですが、この数は間違っています。この補正は誤差を引き起こします。
0 xffと合わせれば、24ビットの高さが0になります。結果は正しいです。
----
Javaの中の1つのbyteは-128~127の範囲であり、Integer.toHexStringのパラメータは元々intであり、&0 xffを行わないと、byteがintに変換されると、負の数に対してビット拡張が行われます。例えば、1つのbyteの-1(即ち0 xffff)は、intの-1に変換されます。
0 xffはデフォルトでは整形ですので、1つのbyteと0 xffが参加してまずそのbyteを整形演算に変換します。このように結果の中の高い24ビットはいずれも0をクリアします。
http://rainsilence.iteye.com/blog/842338
package org.filetype;
/**
*
*/
public enum FileType {
/**
* JEPG.
*/
JPEG("FFD8FF"),
/**
* PNG.
*/
PNG("89504E47"),
/**
* GIF.
*/
GIF("47494638"),
/**
* TIFF.
*/
TIFF("49492A00"),
/**
* Windows Bitmap.
*/
BMP("424D"),
/**
* CAD.
*/
DWG("41433130"),
/**
* Adobe Photoshop.
*/
PSD("38425053"),
/**
* Rich Text Format.
*/
RTF("7B5C727466"),
/**
* XML.
*/
XML("3C3F786D6C"),
/**
* HTML.
*/
HTML("68746D6C3E"),
/**
* Email [thorough only].
*/
EML("44656C69766572792D646174653A"),
/**
* Outlook Express.
*/
DBX("CFAD12FEC5FD746F"),
/**
* Outlook (pst).
*/
PST("2142444E"),
/**
* MS Word/Excel.
*/
XLS_DOC("D0CF11E0"),
/**
* MS Access.
*/
MDB("5374616E64617264204A"),
/**
* WordPerfect.
*/
WPD("FF575043"),
/**
* Postscript.
*/
EPS("252150532D41646F6265"),
/**
* Adobe Acrobat.
*/
PDF("255044462D312E"),
/**
* Quicken.
*/
QDF("AC9EBD8F"),
/**
* Windows Password.
*/
PWL("E3828596"),
/**
* ZIP Archive.
*/
ZIP("504B0304"),
/**
* RAR Archive.
*/
RAR("52617221"),
/**
* Wave.
*/
WAV("57415645"),
/**
* AVI.
*/
AVI("41564920"),
/**
* Real Audio.
*/
RAM("2E7261FD"),
/**
* Real Media.
*/
RM("2E524D46"),
/**
* MPEG (mpg).
*/
MPG("000001BA"),
/**
* Quicktime.
*/
MOV("6D6F6F76"),
/**
* Windows Media.
*/
ASF("3026B2758E66CF11"),
/**
* MIDI.
*/
MID("4D546864");
private String value = "";
/**
* Constructor.
*
* @param type
*/
private FileType(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
タイプ判定コアクラス
package org.filetype;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
*
*/
public final class FileTypeJudge {
/**
* Constructor
*/
private FileTypeJudge() {}
/**
* 16
*
* @param byte
* @return 16
*/
private static String bytesToHexString(byte[] src){
StringBuilder stringBuilder = new StringBuilder();
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF; //java byte int 0xff ?
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
/**
*
*
* @param filePath
* @return
* @throws IOException
*/
private static String getFileContent(String filePath) throws IOException {
byte[] b = new byte[28];
InputStream inputStream = null;
try {
inputStream = new FileInputStream(filePath);
inputStream.read(b, 0, 28);
} catch (IOException e) {
e.printStackTrace();
throw e;
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
throw e;
}
}
}
return bytesToHexString(b);
}
/**
*
*
* @param filePath
* @return
*/
public static FileType getType(String filePath) throws IOException {
String fileHead = getFileContent(filePath);
if (fileHead == null || fileHead.length() == 0) {
return null;
}
fileHead = fileHead.toUpperCase();
FileType[] fileTypes = FileType.values();
for (FileType type : fileTypes) {
if (fileHead.startsWith(type.getValue())) {
return type;
}
}
return null;
}
}
テストクラス
package org.filetype;
public class Test {
/**
* @param args
*/
public static void main(String args[]) throws Exception {
System.out.println(FileTypeJudge.getType("C:\\eclipse-jee-helios-win32.zip"));
}
}
テストクラスを実行して、consolieにzipを表示します。java中byte変換intの場合、なぜ0 xffと演算するのですか?
この問題を分析する前に、下記のコードを見てください。
public static String bytes2HexString(byte[] b) {
String ret = "";
for (int i = 0; i < b.length; i++) {
String hex = Integer.toHexString(b[ i ] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
ret += hex.toUpperCase();
}
return ret;
}
上はbyte[]を16進の文字列に変換しました。ここでb[i]&0 xFFは一つのbyteと0 xFFを演算し、Integer.toHexStringを使って16進の文字列を取得しています。b[i]&0 xFFは演算してもなおintなのに、なぜ0 xFFと演算するのですか?直接Integer.toHexString(b[i]);byteをintに強くしてはいけませんか?答えはだめです
その理由は:
1.byteのサイズは8 bittsでintのサイズは32 bittsです。
2.javaのバイナリは補数形式を採用しています。
ここでまずコンピューターの基礎理論を復習します。
byteはバイトで保存されています。8ビットがあります。すなわち、8ビットが0、1です。
8位の最初のビットは符号ビットであり、
つまり0000 0001は数字の1です。
1000 0000は-1を表しています。
ですから、正数が一番大きいのは0111 1111、つまり127です。
負の数は最大1111 1111、つまり数字-128です。
上に述べたのはバイナリコードですが、javaでは補数コードという形をとっています。以下は補数コードとは何かを紹介します。
1、逆コード:
一つの数が正しければ、その逆コードはもとのコードと同じです。
一つの数が負であれば、記号のビットは1であり、残りの各ビットは原コードに対して逆である。
2、補数:オーバーフローを利用して、減算を加算に変えることができます。
10進数に対しては、9から5を得ると減算できます。
9-4=5 4+6=10なので、6を4の補数にしてもいいです。
加算に書き換える:
9+6=15(上位1、つまりマイナス10)を5.
16進数については、cから5まで減算ができます。
c-7=5 7+9=16は9を7の補数とするからです。
加算に書き換える:
c+9=15(上位1、つまりマイナス16)を5.
コンピュータの中で、もし私達は1バイトで1つの数を表すならば、1バイトは8ビットあって、8ビットを上回って1に進んで、メモリの中で情況は(10000000000)で、進数1は捨てられます。
(1つの数が正であれば、その原コード、逆コード、補数は同じである)
⑵一つの数は負で、一つの記号のビットは1で、残りの各ビットは原コードに対して逆を取り、全体の数は1を加算する。
-1の原コードは 100000 1
-1の逆コードは 11111110
+ 1
-1の補数は 11111111
0の原コードは 0000000
0の逆コードは 11111111(正のゼロと負のゼロの逆符号は同じ)
+1
0の補数は 10000000000(打抜きの1、プラスゼロとマイナスゼロの補数は同じです。)
Integer.toHexStringのパラメータはintであり、&0 xffを行わないと、1 byteがintに変換される場合、intは32ビットであるのに対し、byteは8ビットしかない場合は補足されます。
たとえば、補数11111111の10進数が−1に変換されてintに変換されると11111111111111111111111111111111111111111111の多くの1になります。つまり0 xffffffですが、この数は間違っています。この補正は誤差を引き起こします。
0 xffと合わせれば、24ビットの高さが0になります。結果は正しいです。
----
Javaの中の1つのbyteは-128~127の範囲であり、Integer.toHexStringのパラメータは元々intであり、&0 xffを行わないと、byteがintに変換されると、負の数に対してビット拡張が行われます。例えば、1つのbyteの-1(即ち0 xffff)は、intの-1に変換されます。
0 xffはデフォルトでは整形ですので、1つのbyteと0 xffが参加してまずそのbyteを整形演算に変換します。このように結果の中の高い24ビットはいずれも0をクリアします。