位元組順序標記導致Java 中的CSV 檔案讀取出現問題
位元組順序標記(BOM) 可能出現在某些CSV 的開頭文件,但不是全部。如果存在,BOM 會與檔案的第一行一起讀取,從而在比較字串時造成問題。
以下是解決此問題的方法:
解決方案:
實作一個包裝類別UnicodeBOMInputStream,用於偵測輸入開頭是否存在Unicode BOM溪流。如果偵測到 BOM,可以使用skipBOM() 方法將其刪除。
以下是UnicodeBOMInputStream 類別的範例:
import java.io.IOException; import java.io.InputStream; import java.io.PushbackInputStream; public class UnicodeBOMInputStream extends InputStream { private PushbackInputStream in; private BOM bom; private boolean skipped = false; public UnicodeBOMInputStream(InputStream inputStream) throws IOException { if (inputStream == null) throw new NullPointerException("Invalid input stream: null is not allowed"); in = new PushbackInputStream(inputStream, 4); byte[] bom = new byte[4]; int read = in.read(bom); switch (read) { case 4: if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE) && (bom[2] == (byte) 0x00) && (bom[3] == (byte) 0x00)) { this.bom = BOM.UTF_32_LE; break; } else if ((bom[0] == (byte) 0x00) && (bom[1] == (byte) 0x00) && (bom[2] == (byte) 0xFE) && (bom[3] == (byte) 0xFF)) { this.bom = BOM.UTF_32_BE; break; } case 3: if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF)) { this.bom = BOM.UTF_8; break; } case 2: if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) { this.bom = BOM.UTF_16_LE; break; } else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) { this.bom = BOM.UTF_16_BE; break; } default: this.bom = BOM.NONE; break; } if (read > 0) in.unread(bom, 0, read); } public BOM getBOM() { return bom; } public UnicodeBOMInputStream skipBOM() throws IOException { if (!skipped) { in.skip(bom.bytes.length); skipped = true; } return this; } @Override public int read() throws IOException { return in.read(); } @Override public int read(byte[] b) throws IOException { return in.read(b, 0, b.length); } @Override public int read(byte[] b, int off, int len) throws IOException { return in.read(b, off, len); } @Override public long skip(long n) throws IOException { return in.skip(n); } @Override public int available() throws IOException { return in.available(); } @Override public void close() throws IOException { in.close(); } @Override public synchronized void mark(int readlimit) { in.mark(readlimit); } @Override public synchronized void reset() throws IOException { in.reset(); } @Override public boolean markSupported() { return in.markSupported(); } private enum BOM { NONE, UTF_8, UTF_16_LE, UTF_16_BE, UTF_32_LE, UTF_32_BE } }
用法:
使用UnicodeBOMInputStream 包裝器作為如下:
import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStreamReader; public class CSVReaderWithBOM { public static void main(String[] args) throws Exception { FileInputStream fis = new FileInputStream("test.csv"); UnicodeBOMInputStream ubis = new UnicodeBOMInputStream(fis); System.out.println("Detected BOM: " + ubis.getBOM()); System.out.print("Reading the content of the file without skipping the BOM: "); InputStreamReader isr = new InputStreamReader(ubis); BufferedReader br = new BufferedReader(isr); System.out.println(br.readLine()); br.close(); isr.close(); ubis.close(); fis.close(); fis = new FileInputStream("test.csv"); ubis = new UnicodeBOMInputStream(fis); isr = new InputStreamReader(ubis); br = new BufferedReader(isr); ubis.skipBOM(); System.out.print("Reading the content of the file after skipping the BOM: "); System.out.println(br.readLine()); br.close(); isr.close(); ubis.close(); fis.close(); } }使用UnicodeBOMInputStream 包裝器作為如下:此方法可讓您讀取帶有或不帶有BOM 的CSV 文件,並避免因文件第一行中存在 BOM 而導致的字串比較問題。
以上是在 Java 中讀取 CSV 檔案時如何處理字節順序標記 (BOM)?的詳細內容。更多資訊請關注PHP中文網其他相關文章!