PrintWriter打印流

Writer的子类,既可以接收字符流,也可以接收字节流,还可以接收文件名或者文件对象,非常方便

同时,还可以设置自动刷新以及保持原有格式写入各种文本类型的print方法

PrintWriter的小例子:打印字符录入的大写

   1: //读取键盘录入,打印大写

   2: private static void printWriterMethod() throws IOException

   3: {

   4:     BufferedReader bufr =

   5:         new BufferedReader(new InputStreamReader(System.in));

   6:  

   7:     PrintWriter out = new PrintWriter(System.out,true);

   8:  

   9:     String line = null;

  10:  

  11:     while( (line = bufr.readLine()) != null)

  12:     {

  13:         if("over".equals(line))

  14:             break;

  15:         //只需一条语句,便可打印一行数据,非常方便

  16:         out.println(line.toUpperCase());

  17:     }

  18:     

  19:     out.close();

  20:     bufr.close();

  21: }

SequenceInputStream合并流

序列流,可将多个流合并成一个流,按序列进行读取

可手动指定各个流创建对象,也可将多个流存入集合,利用枚举Enumeration来创建对象

合并和分割流的小例子:

   1: import java.io.*;

   2: import java.util.*;

   3:  

   4: class SequenceInputStreamDemo 

   5: {

   6:     public static void main(String[] args) throws IOException

   7:     {

   8:  

   9:         int num = splitFile(new File("pic.jpg"));

  10:  

  11:         /*

  12:         合并分割后的流

  13:         */

  14:         

  15:         //定义Vector集合存储所有part文件的字节输入流

  16:         Vector<FileInputStream> v = new Vector<FileInputStream>();

  17:  

  18:         for(int i = 1 ; i <= num ; i ++ )

  19:         {

  20:             v.add(new FileInputStream(i+".part"));

  21:         }

  22:  

  23:         Enumeration<FileInputStream> en = v.elements();

  24:  

  25:         FileOutputStream fos = new FileOutputStream("pic1.jpg");

  26:         

  27:         //定义序列流,通过枚举合并所有的输入流

  28:         SequenceInputStream sis = new SequenceInputStream(en);

  29:  

  30:         byte[] buf = new byte[1024];

  31:  

  32:         int len = -1;

  33:  

  34:         while( (len = sis.read(buf)) != -1)

  35:         {

  36:             //将合并后的流写入一个文件

  37:             fos.write(buf,0,len);

  38:         }

  39:  

  40:         fos.close();

  41:         sis.close();    

  42:     }

  43:     

  44:     //分割流

  45:     private static int splitFile(File f) throws IOException

  46:     {

  47:         FileInputStream fis = new FileInputStream(f);

  48:  

  49:         long size = f.length();

  50:  

  51:         byte[] buf = null;

  52:         

  53:         //选择缓冲区大小

  54:         if(size > 1024*1024*5)

  55:             buf = new byte[1024*1024];

  56:         else

  57:             buf = new byte[(int)size/5];

  58:  

  59:         int len = -1;

  60:         int count = 1;

  61:  

  62:         while( (len = fis.read(buf)) != -1)

  63:         {

  64:             //每个缓冲区的内容分别写入不同的part文件

  65:             FileOutputStream fos = new FileOutputStream((count++)+".part");

  66:             fos.write(buf,0,len);

  67:             fos.close();

  68:         }

  69:  

  70:         fis.close();

  71:  

  72:         return count-1;

  73:     }

  74: }

对象的序列化

ObjectInputStream,ObjectOutputStream

将对象存取在硬盘上,叫做对象的持久化存储(存储的是对象的属性值,而不是方法)

想要对对象进行序列化,该对象必须实现Serializable接口,Serializable接口没有方法,称为标记接口,实现过程只是给实现者加入一个序列化的ID:ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L; 其实就是序列号,这个序列号是由变量的声明语句自动生成的,我们也可以自己定义类的序列号

对象序列化的小例子

   1: import java.io.*;

   2:  

   3: class Person implements Serializable

   4: {

   5:     //序列号,保证类型一致

   6:     static final long serialVersionUID = 42L;

   7:  

   8:     //静态变量以及transient修饰的变量不会被序列化

   9:     static String country = "cn";

  10:     transient int grade;

  11:     private String name;

  12:     private int age;

  13:  

  14:     Person(String name,int age,int grade,String country)

  15:     {

  16:         this.name = name;

  17:         this.age = age;

  18:         this.grade = grade;

  19:         this.country = country;

  20:     }

  21:  

  22:     public String toString()

  23:     {

  24:         return name+"::"+age+"::"+grade+"::"+country;

  25:     }

  26: }

  27:  

  28: class ObjectStreamDemo 

  29: {

  30:     public static void main(String[] args) throws Exception

  31:     {

  32:  

  33:         //writeObj();

  34:         readObj();

  35:     }

  36:  

  37:     //将对象写入流中

  38:     private static void writeObj() throws IOException

  39:     {

  40:         ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));

  41:  

  42:         oos.writeObject(new Person("Shawn",30,3,"en"));

  43:         oos.writeObject(new Person("feng",23,6,"usa"));

  44:  

  45:         oos.close();

  46:     }

  47:     

  48:     //将对象从流中读出并打印

  49:     private static void readObj() throws Exception

  50:     {

  51:         ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));

  52:  

  53:         Person p1 = (Person)ois.readObject();

  54:         Person p2 = (Person)ois.readObject();

  55:  

  56:         System.out.println("p1 --- "+p1);

  57:         System.out.println("p2 --- "+p2);

  58:  

  59:         ois.close();

  60:     }

  61: }

我们可以看到,静态变量和transient修饰的变量是不会被序列化到硬盘上的

管道流

PipedInputStream,PipedOutputStream

管道Demo,一个线程写,一个线程读

   1: import java.io.*;

   2:  

   3: //读管道流线程

   4: class Read implements Runnable

   5: {

   6:     private PipedInputStream pis;

   7:  

   8:     Read(PipedInputStream pis)

   9:     {

  10:         this.pis = pis;

  11:     }

  12:  

  13:     public void run()

  14:     {

  15:         try

  16:         {

  17:             byte[] buf = new byte[1024];

  18:         

  19:             int len = -1;

  20:             

  21:             //阻塞方法,读不到数据会等待

  22:             len = pis.read(buf);

  23:  

  24:             System.out.println(new String(buf,0,len));

  25:  

  26:             pis.close();

  27:         }

  28:         catch (IOException e)

  29:         {

  30:             System.out.println("pipe read error!");

  31:         }

  32:         

  33:     }

  34: }

  35:  

  36: //写管道流线程

  37: class Write implements Runnable

  38: {

  39:     private PipedOutputStream pos;

  40:  

  41:     Write(PipedOutputStream pos)

  42:     {

  43:         this.pos = pos;

  44:     }

  45:  

  46:     public void run()

  47:     {

  48:         try

  49:         {

  50:             pos.write("pipe is coming!".getBytes());

  51:  

  52:             pos.close();

  53:         }

  54:         catch (IOException e)

  55:         {

  56:             System.out.println("pipe write error!");

  57:         }

  58:  

  59:     }

  60: }

  61:  

  62: class PipedStreamDemo 

  63: {

  64:     public static void main(String[] args) throws IOException

  65:     {

  66:         PipedInputStream pis = new PipedInputStream();

  67:         PipedOutputStream pos = new PipedOutputStream();

  68:         

  69:         //链接读写管道

  70:         pis.connect(pos);

  71:  

  72:         new Thread(new Read(pis)).start();

  73:  

  74:         new Thread(new Write(pos)).start();

  75:     }

  76: }

随机访问文件流

RandomAccessFile

直接继承Object类,内部封装了字节输入输出流,同时封装了文件的指针,可对基本数据类型进行直接读写,最大的好处是可以实现数据的分段写入,通过seek方法。

用随机访问实现的多线程复制文件(后期会改进代码,完成多线程下载)

   1: import java.io.*;

   2:  

   3: //下载线程

   4: class DownLoadThread implements Runnable

   5: {

   6:     private RandomAccessFile in;

   7:     private RandomAccessFile out;

   8:     private int offset;//偏移量

   9:     private int buf_size;//分配数据量

  10:     private int block_size;//缓冲区大小

  11:  

  12:     //初始化

  13:     DownLoadThread(RandomAccessFile in,RandomAccessFile out,int offset,int buf_size)

  14:     {

  15:         this.in = in;

  16:         this.out = out;

  17:         this.offset = offset;

  18:         this.buf_size = buf_size;

  19:         

  20:         block_size = 1024*512;

  21:         if(buf_size < block_size)

  22:             block_size = buf_size;

  23:  

  24:     }

  25:  

  26:     public void run()

  27:     {

  28:         try

  29:         {        

  30:             System.out.println(Thread.currentThread().getName()+"开始下载...");

  31:             

  32:             //读写流都偏移到指定位置

  33:             in.seek(offset);

  34:             out.seek(offset);

  35:  

  36:             byte[] buf = new byte[block_size];

  37:                 

  38:             int len = -1;

  39:  

  40:             int lastSize = buf_size;

  41:             

  42:             //读取信息并写入到目的地

  43:             while( (len = in.read(buf)) != -1)

  44:             {

  45:                 out.write(buf,0,len);

  46:  

  47:                 lastSize -= len;

  48:                 

  49:                 //分配数据量完成,结束线程

  50:                 if(lastSize == 0)

  51:                     break;

  52:                 if(lastSize < block_size)

  53:                 {

  54:                     block_size = lastSize;

  55:                     buf = new byte[block_size];

  56:                 }

  57:             }

  58:             

  59:             System.out.println(Thread.currentThread().getName()+"下载完成!");

  60:  

  61:             in.close();

  62:             out.close();

  63:             

  64:         }

  65:         catch (IOException e)

  66:         {

  67:             throw new RuntimeException(e);

  68:         }

  69:         

  70:     }

  71: }

  72:  

  73: class MutiDownLoadDemo 

  74: {

  75:     public static void main(String[] args) throws Exception

  76:     {

  77:         //确定源文件和目的文件

  78:         File fin = new File("1.avi");

  79:         File fout = new File("5.avi");

  80:         

  81:  

  82:         multiDownload(fin,fout,12);

  83:  

  84:  

  85:     }

  86:     

  87:     //多线程下载 thread_num为线程数

  88:     private static void multiDownload(File fin,File fout,int thread_num) throws Exception

  89:     {

  90:         RandomAccessFile in = new RandomAccessFile(fin,"r");

  91:  

  92:         RandomAccessFile out = new RandomAccessFile(fout,"rwd");

  93:  

  94:         int len = (int)fin.length();

  95:         

  96:         //确定目的文件大小

  97:         out.setLength(len);

  98:         

  99:         in.close();

 100:         out.close();

 101:  

 102:         System.out.println("-----------File size : "+(len>>20)+" MB--------------");

 103:         System.out.println("-----------Thread num: "+thread_num+"---------");

 104:         

 105:         //确定每个线程分配的数据量

 106:         int buf_size = len/thread_num;

 107:  

 108:         System.out.println("-----------buffer size: "+(buf_size>>20)+" MB-----------");

 109:  

 110:         //开启每个线程

 111:         for(int i = 0 ; i < thread_num ; i ++)

 112:         {

 113:             //"rwd"模式代表可读可写并且线程安全

 114:             new Thread(

 115:                 new DownLoadThread(new RandomAccessFile(fin,"r"),new RandomAccessFile(fout,"rwd"),i*buf_size,buf_size)

 116:                 ).start();

 117:         }

 118:     }

 119: }

基本数据类型流对象

DataInputStream,DataOutputStream

   1: public static void main(String[] args) throws IOException

   2: {

   3:     DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));

   4:  

   5:     dos.writeInt(123);

   6:  

   7:     dos.writeDouble(123.45);

   8:  

   9:     dos.writeBoolean(true);

  10:  

  11:     DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));

  12:  

  13:     System.out.println(dis.readInt());

  14:     System.out.println(dis.readDouble());

  15:     System.out.println(dis.readBoolean());

  16: }

内存作为源和目的的流对象

操作字节数组

ByteArrayInputStream与ByteArrayOutputStream

操作字符数组

CharArrayReader与CharArrayWrite

操作字符串

StringReader 与 StringWriter

字符编码

字符流出现是为了更方便的操作字符,通过InputStreamReader和OutputStreamWriter可以任意指定编码表进行解码转换

编码表

计算机开始只能识别二进制数据,为了更方便的表示各个国家的文字,就将各个国家的文字与二进制数据进行一一对应,形成了一张表,即为编码表

常见的编码表

ASCII:美国标准信息交换码。

用一个字节的7位可以表示。

ISO8859-1:拉丁码表。欧洲码表

用一个字节的8位表示。

GB2312:中国的中文编码表。

GBK:中国的中文编码表升级,融合了更多的中文文字符号。

Unicode:国际标准码,融合了多种文字。

所有文字都用两个字节来表示,Java语言使用的就是unicode

UTF-8:最多用三个字节来表示一个字符

......

编码规则

只有GBK和UTF-8识别中文,GBK向下兼容GB2312

GBK两个字节表示一个字符,UTF-8是1-3个字节表示一个字符,每个字节前面1-3位作为标识头

GBK和UTF-8都兼容ASCII码表

模拟编解码过程代码

   1: public static void main(String[] args) throws Exception

   2: {

   3:     //字符串

   4:     String s = "你好";

   5:     

   6:     //用UTF-8编码表编码s字符串

   7:     byte[] b = s.getBytes("UTF-8");

   8:     

   9:  

  10:     System.out.println(Arrays.toString(b));

  11:     

  12:     //用GBK编码表解码

  13:     String s1 = new String(b,"GBK");

  14:     

  15:     //获取之后发现不是原来的字符串

  16:     System.out.println(s1);

  17:     

  18:     //用GBK重新编码回去

  19:     byte[] b1 = s1.getBytes("GBK");

  20:     

  21:     //再用UTF-8解码

  22:     String s2 = new String(b1,"UTF-8");

  23:  

  24:     System.out.println(s2);

  25:     

  26:     

  27: }

这样做存在一个问题,由于GBK与UTF-8都支持中文,所以UTF-8编解码时有可能会去内部的相似码表去查找,这样编码出来的字符就会与原字符不符,所以一般使用ISO8859-1与中文码表互相编解码转换

一个有趣的小例子

新建一个文本文档,写入“联通”两个字,保存,关闭,再打开,发现变成了一个奇怪的字符,这是为什么呢?

首先windows默认的是ANSI编码,而UTF-8编码的标识头规则如下图

由于记事本是由编码本身的规律判断选取哪个编码表的

所以答案是,“联通”这两个字由ANSI编码之后的码流符合UTF-8的规则,则记事本自动识别是UTF-8的字符,而去查了UTF-8的码表

解决方法,我们只要在联通前面加上任意字符,记事本就不会误判为UTF-8解码了

Java笔记(二十八)……IO流下 IO包中其他常用类以及编码表问题的更多相关文章

  1. angular学习笔记(二十八-附2)-$http,$resource中的promise对象

    下面这种promise的用法,我从第一篇$http笔记到$resource笔记中,一直都有用到: HttpREST.factory('cardResource',function($resource) ...

  2. Java基础学习笔记二十八 管家婆综合项目

    本项目为JAVA基础综合项目,主要包括: 熟练View层.Service层.Dao层之间的方法相互调用操作.熟练dbutils操作数据库表完成增删改查. 项目功能分析 查询账务 多条件组合查询账务 添 ...

  3. 菜鸡的Java笔记 第二十八 - java 包的定义

    包的主要作用以及定义    包的导入操作    系统常见的开发包    jar 程序命令        包的定义        在任何的操作系统之中都有一个统一的共识:同一个目录下不能够存在有相同的文 ...

  4. Java笔记(二十六)……IO流上 字节流与字符流

    概述 IO流用来处理设备之间的数据传输 Java对数据的操作时通过流的方式 Java用于操作流的对象都在IO包中 流按操作的数据分为:字节流和字符流 流按流向不同分为:输入流和输出流 IO流常用基类 ...

  5. Java学习笔记二十八:Java中的接口

    Java中的接口 一:Java的接口: 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明.一个类通过继承接口的方式,从而来继承 ...

  6. Java笔记(二十九)……网络编程

    概述 网络模型 网络通讯的要素 ip地址:网络中设备的标识符 端口:用于标识同一台设备上不同的进程,有效端口:0~65535,其中0~1024是系统使用端口或者保留端口 TCP与UDP UDP特点: ...

  7. Java笔记(二十五)……其他常用API

    System类 工具类全部都是静态方法 常用方法 获取系统属性信息 static PropertiesgetProperties() static StringgetProperty(String k ...

  8. Java笔记(二十二)……Collection集合

    概述 为什么会出现集合类 面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式 数组和集合类同是容器,有何不同 数组虽然也可以存储 ...

  9. 菜鸡的Java笔记 第十八 - java 代码块

    代码块  code block                content (内容)        在程序结构之中使用"{}"定义的内容就称为代码块,但是会根据其声明的位置以及关 ...

随机推荐

  1. 推荐一个优秀的前端框架——Bootstrap

    Bootstrap是Twitter推出的一个开源的用于前端开发的工具包.它由Twitter的设计师Mark Otto和Jacob Thornton合作开发,是一个CSS/HTML框架.Bootstra ...

  2. Visual C++ 对话框增加菜单栏

    1.添加菜单资源     在resourceview视图中右击选择insert,添加一个菜单资源IDR_MENU1,同时设定好响应的菜单项,例 如:         菜单1               ...

  3. python--threading多线程总结

    threading用于提供线程相关的操作,线程是应用程序中工作的最小单元.python当前版本的多线程库没有实现优先级.线程组,线程也不能被停止.暂停.恢复.中断. threading模块提供的类:  ...

  4. Nginx+uWSGI+bottle 在Linux上部署

    在/data/lujianxing/bottle 文件夹中创建三个文件: bottle.py bottle的源文件 a.py from bottle import Bottle, run mybott ...

  5. Python OptionParser学习

    from optparse import OptionParser import sys def main(): p = OptionParser() p.add_option('-n','--nam ...

  6. struts2 查 找总结

    0:38 2013/5/25 查 找 * * |-_-查找全部 Action层的home方法中的查找方法创建时不需要带个查找对象的参数 service层不用组织条件 dao层一条查询所有的hql语句S ...

  7. mvvm windows app DataBinding

    前台html 绑定(view):<div id="aa" data-win-bind="innerText:UserData.word" style=&q ...

  8. poj 2406 Power Strings (kmp 中 next 数组的应用||后缀数组)

    http://poj.org/problem?id=2406 Power Strings Time Limit: 3000MS   Memory Limit: 65536K Total Submiss ...

  9. 学无止境,学习AJAX,跨域(三)

    学习AJAX其实有个很重要的应用,就是为了执行另外几个站点的ASP,返回结果. 真正用起来,发现2个问题,>_> 不许笑,一向做DELPHI,接触ASP不多的我,的确问题大堆. 第一个问题 ...

  10. mongodb 简单部署方案及实例

    mongodb 简单部署方案及实例 转载:http://my.oschina.net/zhuzhu0129/blog/53290 第一节 准备工作 一 安装mongodb  我这里选用rehl 5.6 ...