关于java文件读写、字节流、字符流的一点心得

tanklovelove 2014-09-20 10:57:08
转载]转:关于java文件读写、字节流、字符流的一点心得

一.转载网址:http://my.oschina.net/u/232879/blog/155440
关于编码方式我们不讲,有兴趣自己去看,这里大概提一下。

UTF-16采用等幅编码,即每个字符占2个字节。优点:简单;缺点:西文会膨胀到200%,冗余!而且字与字之间的疆界不好找,容易划分错误,没有考虑好前缀问题。这一点huffman编码做的很好。
UTF-8为不等幅编码,有1到3个字节的不等长度。优点:由于采用了很好的前缀,不会出现字之间疆界不好找和划分错误的情况。缺点:中日韩等文字膨胀到150%,冗余。

现在主要说一下字节流、字符流的区别,顾名思义字节流是以字节为单位读取数据的,而字符流是以字符为单位读取的。我们都知道java采用了两种I/O读写 方式主要有两个超类系:一个是inputstream和outputstream字节流类系;另一个是Reader和Writer字符流类系。使用他们来 读写文本文件时有些要注意的问题:

1、使用inputstream类的子类读取的单位为字节,对于英语字母(只占一个字节)不受任何影响,而中文文字在unicode编码为两个字节(或者以上?),在读取中一个中文文字会被划分为两个(或多个)字节,因而受到影响。
如果将读取到的字节保存在byte[]数组中,为了正确地处理字节到字符的转化应注意如下问题:
对byte[]数组采用toString的方法转化为字符,会导致错误的分割方式生成字符,不能正确地显示字符;而采用String的构造函数String(byte[] b)可以正确的分割构造字符。(或者String(byte[] b, Charset a)带编码方式的构造函数,在知道要读入的文本的编码方式的情况下。)
2、使用Reader类的子类读取的单位为字符,即中文、英文都为两个字节大小,故而都不受影响。
如果将读取到的每一个字符保存到一个字符数组char[] a中问题又来了:
(特别注意!!!)如对字符数组char[]使用toString()函数时同样会遇到错误的分隔,建议使用String类的构造函数String(char[] c)来构造正确的字符划分。
当然有更简便的方法:如果你采用的读取函数是readline()当然不存在如上字符转换的问题(请注意在InputStream类系的子类中是不存在类似readline()这样的函数的,只有read()这样的函数)。

StringBuffer就像一个动态数组一样,我可以保存任意长的char字符,需要时只需将他们读取出来就行了。
在这里我们将读到的每一个byte转化为一个char保存在StringBuffer中,需要时将他们读出再转化为byte,此过程数据不会溢出,精度不会受到损失。

另外好像对转义字符 ’\’,String类的split(String a)函数出现了问题,这是怎么回事?java本身的bug吗?

当一个带完整文件夹路径的文件名,传给File类的mkdir(String FilePathAndName)函数时一定要小心,如果该文件名中包含的文件路径不存在(或者说还未被创建的)的话,直接用此函数创建文件是会出错的, 你需要先一层层的创建好这些路径方可创建该路径下的文件。(创建路径和文件其实是一个函数,本质上也没有什么区别!^_^)

下面是我写的测试程序,代码如下。

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.CharBuffer;


public class FileReaderWriter {


public FileReaderWriter() {
}
public String reader(String fullpath) throws FileNotFoundException
//用readline的方式读取文件内容
{
try
{
String content ="";
File file = new File(fullpath);

if(file.exists())
{
System.out.println("FILE: "+fullpath+" EXIST, Now I will read it!");
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
try {
System.out.println("-----------Now is content of file(Reading):----------");
int n = 0;
for(;;)
{
n++;
String temp = br.readLine();
System.out.println("Line"+n+":");
System.out.println(temp);
content+=temp;
if(temp==null)
{
System.out.println("----------OVER---------");
br.close();
break;
}
}
} catch (IOException ex) {
ex.printStackTrace();
}

}
else
{
System.out.println("FILE:"+fullpath+" is Not EXIST"+"now I will do nothing but exit");
}
return content;
}
catch (FileNotFoundException ex)
{
ex.printStackTrace();
}
return null;
}

public void writer(String fullpath,String content)
{
File f = new File(fullpath);
if(!f.exists())
{
System.out.println("File is not exist! Now I will create it!");
createfile(fullpath);
//f.mkdir();//带有目录时这样创建是不行的
}
FileWriter fw;
try
{
fw = new FileWriter(f);
BufferedWriter bw = new BufferedWriter(fw);
System.out.println("I am Writing Now!");
bw.write(content);
bw.close();
System.out.println("-----------Writing Content:---------");
System.out.println(content);
System.out.println("------------Writing Complete!-------------");
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static void main(String[] args)
{
FileReaderWriter frw = new FileReaderWriter();
//做一下各种文件路径的测试^_^
//String path ="info.txt";
//String path2 = "stream.txt";
//String path ="d:\try1/1\2\info.txt";
//String path2 = "d:\try2\1/2/3\stream.txt";
//String path2 = "\4/2/3\stream.txt";

String path ="1\2\info.txt";
String path2 = "1/2/stream.txt";
String test ="";
String text1 ="Hello, My name is GuiZhiPengn";
String text2 ="我的名字是桂志鹏n";
String text3 ="I come From China! Now I'm Studying in WuHan University of HuBei Province.n";
String text4 ="我来自中国,现在湖北省的武汉大学读书";
test= text1+text2+text3+text4;
frw.writer(path,test);
try {
frw.reader(path);
} catch (FileNotFoundException ex) {
ex.printStackTrace();
}

frw.outputstream(path2,test);
frw.inputstream(path2);
//frw.inputstream("LoginEndpoint.wsdl");

}

public String readerbycharacter(String fullpath) throws IOException
//试图通过一个字节一个字节(或者一个字符一个字符)的读取方式读出流后恢复字符编码,
{
String content ="";
File f = new File(fullpath);
FileReader fr;
int in;
try {
fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr);
StringBuffer sb = new StringBuffer();
//byte[] save = new byte[1000];
//char[] save = new char[1000];
int num =0;
do
{
in = br.read();
if(in!=-1)
{
byte b = (byte)in;//强制转化会出现问题(有中文时,将char转化为byte损失位数,将使中文显示有问题)
char c = (char)in;
sb.append(c);
System.out.println(c);
System.out.println(b);
System.out.println((char)b);
//save[num++] = b;
num++;
}
}while(in!=-1);
br.close();
System.out.println("NUM: "+num);
System.out.println("CHAR Num: " + sb.length());

//content = new String(save);
content = sb.toString();
//content = new String(t);
//content = t.toString();

System.out.println(content);
writer("test.txt",content);
}
catch (FileNotFoundException ex)
{
ex.printStackTrace();
}
return content;
}

public String inputstream(String fullpath)
{

File f = new File(fullpath);
int inbyte = 0;
String content ="";
StringBuffer sb = new StringBuffer();
int num=0;
try {
FileInputStream fin = new FileInputStream(f);
BufferedInputStream bin = new BufferedInputStream(fin);
do
{
try {
inbyte = bin.read();
} catch (IOException ex) {
ex.printStackTrace();
}
if(inbyte!=-1)
{
sb.append((char)inbyte);
//System.out.println((char)inbyte);
num++;
}
}while(inbyte!=-1);
try {
bin.close();
} catch (IOException ex) {
ex.printStackTrace();
}
System.out.println("Num: "+num);
byte[] save = new byte[num];
for(int i = 0; i
{
save[i] = (byte)sb.charAt(i);
}
content = new String(save);

System.out.println(content);
System.out.println("Reading stream success!");

} catch (FileNotFoundException ex) {
ex.printStackTrace();
}
return content;
}

public void outputstream(String fullpath, String content)
{
File f = new File(fullpath);
if(!f.exists())
{
System.out.println("File is not exist! Now I will create it!");
createfile(fullpath);
//f.mkdir();//fullpath中带有目录时这样创建方式是不行的
}
int inbyte = 0;
try {
FileOutputStream fout = new FileOutputStream(f);
BufferedOutputStream bout = new BufferedOutputStream(fout);
try {
bout.write(content.getBytes());
} catch (IOException ex) {
ex.printStackTrace();
}
try {
bout.close();
} catch (IOException ex) {
ex.printStackTrace();
}
System.out.println("Writing Stream Success!");

} catch (FileNotFoundException ex) {
ex.printStackTrace();
}

}

public void createfile(String fullpath)
{
System.out.println("---------In CreateFile Fouction---------");
String[] paths = null;
String propath = null;
File f;
int i;
if(fullpath.indexOf("")!=-1)
{
System.out.println("?????");
//paths = fullpath.split("");此函数执行有问题:java.util.regex.PatternSyntaxException: Unexpected internal error near index 1
fullpath = fullpath.replace('\','/');
}
if(fullpath.indexOf("/")!=-1)
{
System.out.println("!!!!!");
paths = fullpath.split("/");
}
//if(paths[0].indexOf(":")!=-1)

if(paths!=null)
{
for(i = 0; i
{
if(propath!=null)
propath=propath+"/"+paths[i];
else
propath = paths[0];
f = new File(propath);
if(!f.exists())
f.mkdir();
}
}
else
{
f = new File(fullpath);
}
}
}

后记:一位朋友对我的文章给出了很好的答案^_^顶了,谢谢

当操作的对象不需要关心编码问题时应该使用InputStream/OutputStream系列的类。例如读取二进制文件(EXE等)。

当需要关心编码问题时应该使用Reader/Writer系列的类。

String.split()的参数是正则表达式。所以想以分割字符串的话应该这样:str.("");

二.简单的代码分析PrintWriter


class MySendCommondThread extends Thread{
private String commond;
public MySendCommondThread(String commond){
this.commond=commond;
}
publicvoid run(){
//实例化Socket
try {
Socket socket=new Socket(serverUrl,serverPort);
PrintWriter out = new PrintWriter(socket.getOutputStream());
out.println(commond);
out.flush();
} catch (UnknownHostException e) {
} catch (IOException e) {
}
}


}
1.android手册
public PrintWriter (OutputStream out)

Constructs a new PrintWriter with out as its target stream. By default, the new print writer does not automatically flush its contents to the target stream when a newline is encountered.

Parameters
out the target output stream
2.分析
这里使用的是PrintWriter的out构造函数,这个构造函数的唯一参数是OutputStream,在这个实例中是sockt.getOutPutStream(),即将字符流写入到socket的输出流中。
然后在PrintWriter实例化对象out中,调用了println(String str)方法即out.println(commond),也就是实现将commond换行显示出来。
在使用out的构造函数中,由于不能像
public PrintWriter (OutputStream out, boolean autoFlush)

一样将缓冲区的数据挤出,因此需要用到out.flush()方法将缓冲区的数据手动挤出。
...全文
5465 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
Linda L 2015-12-07
  • 打赏
  • 举报
回复
代码结构很难看,还是发表成博客比较好
白开水MD5 2014-09-20
  • 打赏
  • 举报
回复
不错不错,加油

50,528

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧