《Java7编程高级进阶》(三)
来源:互联网 发布:湘雅大数据 编辑:程序博客网 时间:2024/06/03 12:39
- io编码
- InputStream的read方法
- available
- InputStream的write方法
- InputReader字符流的read方法
- OutputStream的write方法
- BufferReader和BufferWriter
- 字节流与字符流
- nio包下的一些常用方法
- 读写对象OutputObjectInputObject
- IO数据处理
- PushbackInputStream
- Vector
- SequenceInputStream
- tip
- PrintStream
- CharArrayWriter
io编码
在io中分为字节、字符操作,面向字节的文件工作在8位编码上,面向字符的工作在16位的unicode编码上,其中每一个字符(unicode)是由两个字节数据组成。
InputStream的read方法
read()这个方法是用来读取数据,每次读取一个字节,返回的是下一个数据字节,说明文件指针不是指向第一个字节,而是第一个字节前面的一个,如果读到末尾返回-1。
byte[] b = new byte[3];len = in.read(b)
read(byte[] b)这个方法是每次读取b.length长度的字节,返回是读入缓冲区的字节总数。
available
这个方法是返回不受阻塞地从此输入流中读取(或跳过)的估计剩余字节数,如果是本地文件,我们通常使用这个方法来获取文件总长度,如果在网络,你已经打开输出流,但是没有数据传过来,就阻塞,所以返回为0.在某些情况下,非阻塞的读取(或跳过)操作在执行很慢时看起来受阻塞,例如,在网速缓慢的网络上读取大文件时。
InputStream的write方法
write(int len)将指定字节写入到输出流中。
write(byte[] b)将 b.length 个字节从指定 byte 数组写入此文件输出流中。
flush()这个方法刷新缓冲区的内容到输出流。(这个方法是非常有用的,在多用户的情况下,不同的线程或用户之间要维持数据额的一致性,立即刷新就变得很重要)
正常如果使用这种读写,是配合使用,要么全是一个字节读写,要么就是字节数组读写。
InputReader(字符流)的read方法
read()返回读取的字符编码,如果已到达流的末尾,则返回 -1
OutputStream的write方法
write()返回 指定要写入字符的 int。
BufferReader和BufferWriter
在前面,我们为了方便读写,我们都自己申明了缓冲区。而这两个类内置了java的缓冲区,请记住,不管你是读取单个字符,还是512个字节,均需要相同数量的I/O操作,因此,使用缓冲区将更加高效。
newLine() 写入一个行分隔符。行分隔符字符串由系统属性 line.separator 定义,并且不一定是单个新行 (‘\n’) 符。
readLine() 读取一个文本行。通过下列字符之一即可认为某行已终止:换行 (‘\n’)、回车 (‘\r’) 或回车后直接跟着换行,包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null 。
flush(),在缓冲流中,它会在文件写完后,关闭输出流的时候,自动关闭,而不需要手动,如果你着急,在没有关闭流,之前强制写到文件中,就需要此方法。
字节流与字符流
使用字符流的好处:
- 他们处理unicode字符集中的任何字符,而字节流金限于ISO Latin8位字节。
- 使用字符流的程序可以很容易进行国际化。
- 字符流使用内部缓存,本质比字节流高效。
通常情况下,使用InputStream/OutputStream类针对图像文件,声音文件、视频等写入二进制数据、ascll文件;要读写基于unicode文本文件,还是使用字符流。
nio包下的一些常用方法
遍历当前文件夹下的文件夹和文件,如果有子文件夹不会遍历,并且它不会遍历文件,会报不是文件目录异常。( 注意啦如果是文件夹就直接文件名,没有后缀格式名)
DirectoryStream<Path> d = null; Path ps = Paths.get("c:\\lib"); try { d = Files.newDirectoryStream(ps); for(Path p:d) { System.out.println(p.getFileName()); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(d!=null) { try { d.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
文件的过滤
Path p = Paths.get("c:\\hello"); DirectoryStream<Path> ds = null; try { ds = Files.newDirectoryStream(p, "*.{txt}"); //这个是文件列举的时候过滤文件格式 for(Path p1:ds) { System.out.println(p1.getFileName()); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(ds!=null) { try { ds.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }//这种方式局限就是只是过滤了后缀文件格式
下面就是自定义过滤文件条件:
Path p = Paths.get("c:\\hello"); DirectoryStream.Filter<Path> ds = null; DirectoryStream<Path> ds1 = null; ds = new DirectoryStream.Filter<Path>() {//后者必须指定泛型,会影响方法参数类型 @Override public boolean accept(Path entry) throws IOException { // TODO Auto-generated method stub return Files.size(entry)==9l; //Files这个方法是用来计算文件大小,单位字节,返回是长整型,所以9后面要加表示为长整型 //该方法显示接受返回结果为true的文件。 } }; try { ds1 = Files.newDirectoryStream(p, ds); //注意DirectoryStream.Filter这个是没有迭代器可以遍历,必须通过DirectoryStream来遍历 for(Path p1:ds1) { System.out.println(p1.getFileName()); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(ds1!=null) { try { ds1.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
读写对象OutputObject、InputObject
先创建对象
public class Test77 implements Serializable { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Test77(String name, int age) { super(); this.name = name; this.age = age; } @Override public String toString() { // TODO Auto-generated method stub return name + " " + age; }}//需要注意的事,对象创建一定要实现Serializable,不然后面写入,会报异常,没有实现该接口。
public void writeObject() { ObjectOutputStream oos = null; try { oos = new ObjectOutputStream(new FileOutputStream(new File("c:\\student.dat"))); Test77 t = new Test77("laoqiang", 12); oos.writeObject(t);//这里需要注意一个一个对象的写。 Test77 t1 = new Test77("laoqiang1", 22); oos.writeObject(t1); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(oos!=null) { try { oos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public void readObject() { ObjectInputStream ois = null; try { ois =new ObjectInputStream(new FileInputStream(new File("c:\\student.dat"))); for(int i = 0;i<2;i++) { Object o = ois.readObject(); System.out.println(o.toString()); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if(ois!=null) { try { ois.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
I/O数据处理
在Java很多时候,还是注重的是数据的处理,数据很多都是以字节数组的形式出现,为了提高读写效率,有了缓冲区,其实缓冲区就是字节数组。数据以原始的二进制传输是最节省带宽。ByteArrayOutputStream、ByteArratInputStream只处理二进制数据。而DataOutputStream和DataInputStream是主要针对数据对象类。
ByteArrayOutputStream、ByteArratInputStream内部自带缓冲区的。
DataOutputStream和DataInputStream是成对使用的,如果用其他流写进的数据是不可以用DataInputStream
读取。
DataOutputStream和DataInputStream:数据输入、输出流允许应用程序以与机器无关方式从底层输入、输出流中读取基本 Java 数据类型。
特别注意,使用DataOutputStream和DataInputStream,以什么顺序写入,就必须按照什么顺序读取。否测会出现乱码或者异常。
FileOutputStream fos = null; try { fos = new FileOutputStream(new File("c:\\java.txt")); } catch (FileNotFoundException e2) { // TODO Auto-generated catch block e2.printStackTrace(); } DataOutputStream dos = new DataOutputStream(fos); try { dos.writeInt(12); dos.writeDouble(2.909089); dos.writeLong(124566778); dos.writeUTF("你好"); dos.writeByte(97); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } FileInputStream fis = null; try { fis = new FileInputStream(new File("c:\\java.txt")); } catch (FileNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } DataInputStream dis = new DataInputStream(fis); try { System.out.println(dis.readInt()); System.out.println((Double)dis.readDouble()); long l = dis.readLong(); System.out.println(l); System.out.println((String)dis.readUTF()); System.out.println((Byte)dis.readByte()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
PushbackInputStream
对于这个流,大家可能接触不是太多。它主要在读取的时候,添加一个功能就是取消读取,将字节推回到缓冲区中。而这就给了我们的机会,去对想要处理的字节和不想要处理的字节,提供了方便,话不多少,下面两个例子:
public static void main(String[] args) { //我们的需求就是在输入eclise控制台输入字节,用*代替你的字节中的.并输出 PushbackInputStream pis= new PushbackInputStream(System.in,3); char c = 0; char c1 = 0; try { while((c = (char) pis.read())!='q') { //www.bai.com System.out.print(c); if((c1=(char) pis.read())=='.') {//这里的读,是下一个字节的读取 System.out.print("*"); }else { pis.unread(c1);//如果不是你想要的推回到缓冲区,下次开始读的还是这个推回的字节 } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
/* * 这个例子,就是键盘录入字节,如果小数点后面联系两个零,就换成**。 */ char c = 0; char c1 = 0; char c2 = 0; PushbackInputStream pis= new PushbackInputStream(System.in,3); try { while((c= (char) pis.read())!='e') { if(c=='.') { System.out.print("."); if((c1=(char) pis.read())=='0') { if((c2=(char) pis.read())=='0') { System.out.println("**"); }else { pis.unread(c2); pis.unread(c1); } }else { pis.unread(c1); } }else { System.out.print(c); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } //在这个例子中,我们需要注意,就是unread方法只能推回1个字节,如果要推回几个,需要在PushbackInputStream 指定回退缓冲区size,否则会报出io异常。
Vector
在这里补充将一个知识,之前也没有怎么使用。Vector中文意思:向量。它和数组一样都是用来存储。但是不同的是,它可以动态自增或者缩减长度。下面介绍它的简单使用:
在默认情况下:Vector初始化的时候size是0,这个是表示Vector的元素个数,一开始你没有,当你增加的话,这个数会跟着变化。
构造函数
Vector() 构造一个空向量,使其内部数据数组的大小(初始容量)为 10,其标准容量增量为零。
Vector(int initialCapacity, int capacityIncrement) 使用指定的初始容量(比如是100,就是到了100的时候才自动增量)和容量增量构造一个空的向量。
- capacityIncrement 容量增量
- setsize()可以用来设置Vector中的容量,在这里需要说明就是你用add(int index,E e)如果index超过size()方法值,会报错的。
- capacity() 这个是获取容量的值
- 在构造函数中,如果自己设置增量,那么当数组不够的时候就可以进行按设定的增量加,默认标准增量10.
SequenceInputStream
这个输入流提供了逻辑连接,可以把多个输入流合并起来,转化为单个输入流。下面举的例子,就是通过从多个文件中获取流,通过转化为单个流,然后写到一个文件中。
Enumeration其实是多个条目的索引列表,有兴趣的可以自己看,这里只是简单使用。
static Vector filename = new Vector(); static Vector fileininputstream = new Vector(); public static void main(String[] args) { getFilesName(); getFilesInputStream(); WriteToFile(); } /* * 将多个文件流写到一个文件中 */ private static void WriteToFile() { // TODO Auto-generated method stub try { OutputStream out = new FileOutputStream("c:\\hello8.txt"); SequenceInputStream sis = new SequenceInputStream(fileininputstream.elements()); byte[] b = new byte[4096]; int len =0; while((len=sis.read(b))!=-1) { out.write(b, 0, len); } System.out.println(b.length); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /* * 获取对应的多个文件输入流 */ private static void getFilesInputStream() { // TODO Auto-generated method stub Enumeration e = filename.elements(); while(e.hasMoreElements()) { InputStream in = null; try { in= new FileInputStream((String)e.nextElement()); } catch (FileNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } fileininputstream.addElement(in); } } /* * 用来从键盘获取文件名 */ private static void getFilesName() { // TODO Auto-generated method stub String content = null; BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); try { while((content=br.readLine())!=null) { if(content.equals("over")) { break; } System.out.println("每次添加的文件名"+content); filename.add("c:\\"+content+".txt"); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
tip
Java的字符集是采用的是unioncode编码,一个字符是占两个字节。
PrintStream
PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式,打印的所有字符都使用平台的默认字符编码转换为字节
String s = "laoqiang"; try { PrintStream ps = new PrintStream("f:\\testjava\\test1.txt"); ps.print('a'); ps.print(12); ps.print("laoqiang"); ps.print(true); ps.printf("你好%s",s);//这个就类似c语言格式化输出列表 boolean b= ps.checkError();//PrintStream 永远不会抛出 IOException;而是, //异常情况仅设置可通过 checkError 方法测试的内部标志 System.out.println(b); ps.flush();
CharArrayWriter
此类实现一个可用作 Writer 的字符缓冲区。缓冲区会随向流中写入数据而自动增长。
CharArrayWriter caw = new CharArrayWriter(50); System.out.println(caw.size()); caw.write(97); try { caw.write("laoqiang"); String s = caw.toString();//将输出流中的数据转化为字符串。 System.out.println(s); char[] c = caw.toCharArray();//将输出流中的数据转变成字符数组 for(char c1:c) { System.out.println(c1); } //上面这些只是将东西写到缓冲区中,并不是真正的写在文件上,那么这个存在的 //意义是,通过其他的流去封装,提高效率。 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(caw.size()); //通过上面测试我们发现size打印出来的并不是我们指定的 //缓冲区的大小,而是缓冲区中实际的字符个数
- 《Java7编程高级进阶》(三)
- 《Java7编程高级进阶》(二)
- 《Java7编程高级进阶》(一)
- final关键字[java7高级进阶]
- static关键字[java7高级进阶]
- java接口[java7高级进阶]
- 对象可见性规则[java7高级进阶]
- 高级编程之网络编程(三)
- Java7新特性(三)DI
- Java7线程学习笔记(三)
- ASP 3.0高级编程(三)
- 高级编程之进程(三)
- Windows高级编程学习笔记(三)
- Python高级编程(三)数据库
- 《Unix环境高级编程》 总结 (三)
- C++高级编程(三)动态内存
- python 高级编程 三
- UNIX_C 高级编程<三>
- 是否影响缓存代码测试
- Reverse Nodes in k-Group
- myeclipse 检出Git 上的项目
- Other_模板
- App踩坑系列
- 《Java7编程高级进阶》(三)
- numpy.chararray.flat的使用
- 从底层驱动 到上层APP的流程(2)
- HDU 1505(动态规划-最大子矩阵)
- 神经网络机器翻译模型介绍-GNMT
- 双向级联中的一对多导航
- HashMap类源码解析
- tomcat启动成功并能运行项目,但无法显示那只小猫
- 运用反射从bean对象中取出属性 页面显示list优化