一.转载网址: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字符流类系。使用他们来 读写文本文件时有些要注意的问题:
0. java中BufferedInputStream类相比InputStream类,提高了输入效率,增加了输入缓冲区的功能。
InputStream流是指将字节序列从外设或外存传递到应用程序的流
BufferedInputStream流是指读取数据时,数据首先保存进入缓冲区,其后的操作直接在缓冲区中完成。
继承关系是这样的:
Java.lang.Object
Java.io.InputStrean
Java.io.FilterInputStream
Java.io.BufferedInputStream
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 -> FileReader->BufferedReader
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;
}
二. File -> FileWriter->BufferedWriter
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.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 -> FileInputStream->BufferedInputStream
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;
}
四. File -> FileOutputStream->BufferedOutputStream
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
五. OutputStream -> 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()方法将缓冲区的数据手动挤出。
另外,关于从inputStream中读取的例子,可参考下面从Socket中读取数据的示例。
public class ServerThread implements Runnable {
// 定义当前线程所处理的Socket
Socket s = null;
// 该线程所处理的Socket所对应的输入流
六. InputStream -> InputStreamReader->BufferedReader
BufferedReader br = null;
public ServerThread(Socket s) throws IOException {
this.s = s;
// 初始化该Socket对应的输入流
br = new BufferedReader(new InputStreamReader(s.getInputStream(),
"uft-8"));
}
@Override
public void run() {
try
{
String content = null;
//采用循环不断从Socket中读取客户端发送过来的数据
while((content = readFromClient()) != null)
{
//遍历socketList中的每个socket
//将读到的内容向每一个socket发送一次
for(Socket s : MyServer.socketList)
{
OutputStream os = s.getOutputStream();
os.write((content + "\n").getBytes("utf-8"));
}
}
}
catch(IOException e)
{
e.printStackTrace();
}
}
//定义读取客户端数据的方法
private String readFromClient() {
try
{
return br.readLine();
}
//如果捕捉到异常,表明该Socket对应的客户端已经关闭
catch(IOException e)
{
//删除该Socket
MyServer.socketList.remove(s);
}
return null;
}
}
七. BufferedOutputStream和ByteArrayOutputStream区别
也有一部分是自己加上去的,以备后用。
众所周知BufferedOutputStream是一个缓冲数据输出流接口, ByteArrayOutputStream则是字节数组输出流接口. 这2个输出流都是我们经常用到的, 它们都是OutputStream的子类,而什么时候选择用它们呢, 这个就要看你运用到什么应用场景下了.
下来先来看下源码吧.
1.BufferedOutputStream会首先创建一个默认的容器量, capacity = 8192 = 8KB, 每次在写的时候都会去比对capacity是否还够用, 如果不够用的时候, 就flushBuffer(), 把buf中的数据写入对应的outputStream中, 然后将buf清空, 一直这样等到把内容写完. 在这过程中主要起到了一个数据缓冲的功能.
- public synchronized void write(byte b[], int off, int len) throws IOException {
- // 在这判断需要写的数据长度是否已经超出容器的长度了,如果超出则直接写到相应的outputStream中,并清空缓冲区
- if (len >= buf.length) {
- flushBuffer();
- out.write(b, off, len);
- return;
- }
- // 判断缓冲区剩余的容量是否还够写入当前len的内容,如果不够则清空缓冲区
- if (len > buf.length - count) {
- flushBuffer();
- }
- // 将要写的数据先放入内存中,等待数据达到了缓冲区的长度后,再写到相应的outputStream中
- System.arraycopy(b, off, buf, count, len);
- count += len;
- }
- private void flushBuffer() throws IOException {
- if (count > 0) {
- // 把写入内存中的数据写到构造方法里传入的OutputStream句柄里, 并把容量大小清楚
- out.write(buf, 0, count);
- count = 0;
- }
- }
2.普通的OutputStream, 例如ByteArrayOutputStream也会首先创建一个默认的容器量, capacity = 32 = 32b, 每次在写的时候都会去比对capacity是否还够用, 如果不够用的时候, 就重新创建buf的容量, 一直等到内容写完, 这些数据都会一直处于内存中.
- public synchronized void write(byte b[], int off, int len) {
- if ((off < 0) || (off > b.length) || (len < 0) ||
- ((off + len) > b.length) || ((off + len) < 0)) {
- throw new IndexOutOfBoundsException();
- } else if (len == 0) {
- return;
- }
- // 不断对自己的容量进行相加
- int newcount = count + len;
- // 如果新的容量大小已经超过了现有的大小时,则重新开辟新的内存区域来保存当前的数据
- if (newcount > buf.length) {
- buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
- }
- System.arraycopy(b, off, buf, count, len);
- count = newcount;
- }
注释中已经对这个类进行了详细的解释
总结 : 当你资源不足够用时,选择BufferedOutputStream是最佳的选择, 当你选择快速完成一个作业时,可以选择ByteArrayOutputStream之类的输出流