遇到的问题
在用socket通信传输一个pdf文件以及其他的非txt文件的时候总是传到服务端的文件出错,后来发现是在用字符流和字节流在读取各种文件上的差别所导致的
java读取文件的方式
字节流读取:InputStream和OutPutStream,其读取的方式按字节读取,这个常用于读取原始数据。
字符流读取:Reader和Writer,按字节读取数据,java里面一个字符对应两个字节
为什么会有时候会出现乱码
在计算机中常会涉及到编码问题,那么在字符流读取文件的时候也会遇到一些问题,典型的就是在读取txt文件的时候再保存遇到的乱码,在java里面一个字符对应两个字节,但是在UTF-8的编码中有时候一个汉字可能对应的是三个字节,那么这个时候在读取的时候不指定编码的话会造成读取文件的乱码现象
一个txt文件假设是GBK编码的话,在以字符流读取的时候若依GBK读取就会造成问题
测试(JDK1.8,IDEA,默认编码UTF-8,txt文件编码GBK)
测试一
写了一个代码测试了下:
在以字节流去读取pdf格式和其他格式的文件都没问题,但是字节流读取之后保存为String再写入文件会导致pdf等文件出错:代码如下
此时会导致pdf文件全部是白的,音乐等文件全部错误,而且txt格式的文件的文字全部变成拷斤棍,至于拷斤棍百度了下是由于字符编码问题,
File file1 =new File("D:\\disk\\1\\README.doc");
File file2 =new File("D:\\disk\\tes.doc");
Reader reader =new InputStreamReader(new FileInputStream(file1));
int len;
char[] a =new char[1024];
StringBuffer sb =new StringBuffer();
while ((len=reader.read(a))!= -1) //以字节流去读pdf文件
{
sb.append(new String(a,0,len));
}
reader.close();
FileWriter fileWriter = new FileWriter(file2); // 将读取出来的额String数据直接写入
fileWriter.write(sb.toString());
fileWriter.flush();
fileWriter.close();
测试二
将读取之后的String再次变为字节流然后再进行读取再直接以字节流写入:
此时如同前面一个代码结果一样,除了txt有编码问题之外的文件都有问题
// File file1= new File("D:\\disk\\1\\Java锁.pdf");
// File file2 =new File("D:\\disk\\test1.pdf");
// File file1 =new File("D:\\disk\\1\\Java锁.txt");
// File file2 =new File("D:\\disk\\test1.txt");
// File file1 =new File("D:\\disk\\1\\Unit.wma");
// File file2 =new File("D:\\disk\\test1.wma");
File file1 =new File("D:\\disk\\1\\README.doc");
File file2 =new File("D:\\disk\\test1.doc");
InputStream in =null;
OutputStream out =null;
try{
in= new FileInputStream(file1);
byte[] bytes= new byte[1024];
int read =0;
StringBuffer sb =new StringBuffer();
while ((read =in.read(bytes))!= -1)
{
sb.append(new String(bytes,0,read));
}
System.out.println("a");
InputStream inputStream =new ByteArrayInputStream(sb.toString().getBytes());
byte[] re =new byte[1024];
int haveRead= 0;
FileOutputStream fileOutputStream =new FileOutputStream(file2);
while ((haveRead =inputStream.read(re))!= -1)
{
fileOutputStream.write(re,0,haveRead);
}
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}finally {
in.close();
}
}
测试三:
全部以GBK格式读取和以GBK格式写入,除了txt文件正常以外其他的文件全部出错
File file1 =new File("D:\\disk\\1\\Java锁.txt");
// File file2 =new File("D:\\disk\\test4.txt");
// File file1 =new File("D:\\disk\\1\\Unit.wma");
// File file2 =new File("D:\\disk\\test4.wma");
File file1 =new File("D:\\disk\\1\\README.doc");
File file2 =new File("D:\\disk\\test4.doc"); //拷斤棍
FileInputStream fileInputStream =new FileInputStream(file1);
Reader reader =new InputStreamReader(fileInputStream,"GBK"); // txt测试GBK结果正确 DOC测试以UTF-8测试结果:拷斤棍 //
char[] chars =new char[1024];
int read=0;
StringBuffer sb =new StringBuffer();
while((read=reader.read(chars))!= -1)
{
sb.append(new String(chars,0,read));
}
FileOutputStream fileOutputStream =new FileOutputStream(file2);
Writer writer =new OutputStreamWriter(fileOutputStream,"GBK");
writer.write(sb.toString());
writer.flush();
writer.close();
所以在java里面对文件的读写最好以字节流写入:此时无论是各种文件都没问题,对于字符流的使用感觉是在一些需要编码的文件,即类似于txt的文本文件。
File file1 =new File("D:\\disk\\1\\Java锁.pdf");
// File file2 =new File("D:\\disk\\copy.pdf");
// File file1 =new File("D:\\disk\\1\\Java锁.txt");
// File file2 =new File("D:\\disk\\copy.txt");
// File file1 =new File("D:\\disk\\1\\Unit.wma");
// File file2 =new File("D:\\disk\\copy.wma");
File file1 =new File("D:\\disk\\1\\README.doc");
File file2 =new File("D:\\disk\\copy.doc");
InputStream in =null;
OutputStream out =null;
try{
in= new FileInputStream(file1);
out=new FileOutputStream(file2);
byte[] bytes= new byte[1024];
int read =0;
StringBuffer sb =new StringBuffer();
while ((read =in.read(bytes))!= -1)
{
out.write(bytes,0,read); // 直接以字节流的方式输出到文件
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
in.close();
out.close();
}
全部代码
import java.io.*;
/**
* Created by szh on 2017/3/26.
*/
public class FileTest {
/*
文件以字节流读取
1.以这种方式读取非文档的
*/
public static void tes() throws IOException {
// File file1 =new File("D:\\disk\\1\\Java锁.pdf");
// File file2 =new File("D:\\disk\\tes.pdf");
// File file1 =new File("D:\\disk\\1\\Java锁.txt");
// File file2 =new File("D:\\disk\\tes.txt");
// File file1 =new File("D:\\disk\\1\\Unit.wma");
// File file2 =new File("D:\\disk\\tes.wma");
File file1 =new File("D:\\disk\\1\\README.doc");
File file2 =new File("D:\\disk\\tes.doc");
Reader reader =new InputStreamReader(new FileInputStream(file1));
int len;
char[] a =new char[1024];
StringBuffer sb =new StringBuffer();
while ((len=reader.read(a))!= -1) //以字节流去读pdf文件
{
sb.append(new String(a,0,len));
}
reader.close();
FileWriter fileWriter = new FileWriter(file2); // 将读取出来的额String数据直接写入
fileWriter.write(sb.toString());
fileWriter.flush();
fileWriter.close();
}
/*
以字节流来读取文件
*/
public static void test2() throws IOException {
// File file1 =new File("D:\\disk\\1\\Java锁.pdf");
// File file2 =new File("D:\\disk\\test2.pdf");
// File file1 =new File("D:\\disk\\1\\Java锁.txt");
// File file2 =new File("D:\\disk\\test2.txt");
// File file1 =new File("D:\\disk\\1\\Unit.wma");
// File file2 =new File("D:\\disk\\test2.wma");
File file1 =new File("D:\\disk\\1\\README.doc");
File file2 =new File("D:\\disk\\test2.doc");
byte[] sendBytes = new byte[1024];
int length = 0;
StringBuffer sb =new StringBuffer();
FileInputStream fileInputStream =new FileInputStream(file1);
while((length = fileInputStream.read(sendBytes, 0, sendBytes.length)) > 0){ // 将文件读取为String
sb.append(new String(sendBytes, 0, length));
}
FileWriter fileWriter = new FileWriter(file2); // 这里会导致读取出来的txt文字都是拷斤棍
fileWriter.write(sb.toString());
fileWriter.flush();
fileWriter.close();
}
/*
以字节流读取但是不读取为String
*/
public static void copy() throws IOException {
// File file1 =new File("D:\\disk\\1\\Java锁.pdf");
// File file2 =new File("D:\\disk\\copy.pdf");
// File file1 =new File("D:\\disk\\1\\Java锁.txt");
// File file2 =new File("D:\\disk\\copy.txt");
// File file1 =new File("D:\\disk\\1\\Unit.wma");
// File file2 =new File("D:\\disk\\copy.wma");
File file1 =new File("D:\\disk\\1\\README.doc");
File file2 =new File("D:\\disk\\copy.doc");
InputStream in =null;
OutputStream out =null;
try{
in= new FileInputStream(file1);
out=new FileOutputStream(file2);
byte[] bytes= new byte[1024];
int read =0;
StringBuffer sb =new StringBuffer();
while ((read =in.read(bytes))!= -1)
{
out.write(bytes,0,read); // 直接以字节流的方式输出到文件
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
in.close();
out.close();
}
}
/*
将文件以字节流的方式读取文件转为String但是又重新将String转为字节流然后写入
*/
public static void test1() throws IOException {
// File file1= new File("D:\\disk\\1\\Java锁.pdf");
// File file2 =new File("D:\\disk\\test1.pdf");
// File file1 =new File("D:\\disk\\1\\Java锁.txt");
// File file2 =new File("D:\\disk\\test1.txt");
// File file1 =new File("D:\\disk\\1\\Unit.wma");
// File file2 =new File("D:\\disk\\test1.wma");
File file1 =new File("D:\\disk\\1\\README.doc");
File file2 =new File("D:\\disk\\test1.doc");
InputStream in =null;
OutputStream out =null;
try{
in= new FileInputStream(file1);
byte[] bytes= new byte[1024];
int read =0;
StringBuffer sb =new StringBuffer();
while ((read =in.read(bytes))!= -1)
{
sb.append(new String(bytes,0,read));
// out.write(bytes,0,read);
System.out.println(read+"-----------read的值");
}
System.out.println("a");
InputStream inputStream =new ByteArrayInputStream(sb.toString().getBytes());
byte[] re =new byte[1024];
int haveRead= 0;
FileOutputStream fileOutputStream =new FileOutputStream(file2);
while ((haveRead =inputStream.read(re))!= -1)
{
fileOutputStream.write(re,0,haveRead);
}
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}finally {
in.close();
}
}
/*
修改编码
*/
public static void test3() {
// File file1 =new File("D:\\disk\\1\\Java锁.pdf");
// File file2 =new File("D:\\disk\\copy.pdf");
// File file1 = new File("D:\\disk\\1\\Java锁.txt");
// File file2 = new File("D:\\disk\\test3.txt");
// File file1 =new File("D:\\disk\\1\\Unit.wma");
// File file2 =new File("D:\\disk\\test3.wma");
File file1 =new File("D:\\disk\\1\\README.doc");
File file2 =new File("D:\\disk\\test3.doc");
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(file1);
out = new FileOutputStream(file2);
byte[] bytes = new byte[1024];
int read = 0;
StringBuffer sb = new StringBuffer();
while ((read = in.read(bytes)) != -1) {
sb.append(new String(bytes, 0, read));
}
InputStream inputStream = new ByteArrayInputStream(sb.toString().getBytes());
byte[] re = new byte[1024];
int haveRead = 0;
FileOutputStream fileOutputStream = new FileOutputStream(file2);
StringBuffer sb2 = new StringBuffer();
while ((haveRead = inputStream.read(re)) != -1) {
// fileOutputStream.write(re,0,haveRead);
sb2.append(new String(re, 0, haveRead));
}
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "GBK"); // 在这里转换的话会导致都是?
outputStreamWriter.write(sb2.toString());
outputStreamWriter.close();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} finally {
}
}
public static void test4() throws IOException {
// File file1 =new File("D:\\disk\\1\\Java锁.txt");
// File file2 =new File("D:\\disk\\test4.txt");
// File file1 =new File("D:\\disk\\1\\Unit.wma");
// File file2 =new File("D:\\disk\\test4.wma");
File file1 =new File("D:\\disk\\1\\README.doc");
File file2 =new File("D:\\disk\\test4.doc"); //拷斤棍
FileInputStream fileInputStream =new FileInputStream(file1);
Reader reader =new InputStreamReader(fileInputStream,"UTF-8"); // txt测试GBK结果正确 DOC测试以UTF-8测试结果:拷斤棍 //
char[] chars =new char[1024];
int read=0;
StringBuffer sb =new StringBuffer();
while((read=reader.read(chars))!= -1)
{
sb.append(new String(chars,0,read));
}
FileOutputStream fileOutputStream =new FileOutputStream(file2);
Writer writer =new OutputStreamWriter(fileOutputStream,"UTF-8");
writer.write(sb.toString());
writer.flush();
writer.close();
}
public static void main(String args[]) throws IOException {
tes();
test2();
copy();
test1();
test3();
test4();
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。