疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java之IO处理


 

   

  File文件基础

  文件与目录抽象路径名称的表示,其构造方法有四个

  File(File parent,String child):从抽象父目录下创建一个File实例。

  File(String parent,String child):从父目录下创建一个File实例。

  File(String pathname):从指定路径下创建一个File实例。

  File(URI path):从URI转换成抽象路径下创建一个File实例。

  listFiles()方法:返回一个抽象路径名数组,这些抽象路径名表示目录中的子项(文件或目录)

  [java]

  File file = new File("/home/colin");

  File[] childs = file.listFiles();

  listFiles(FileFilter filter):FileFilter是抽象路径名的过滤器,可以用于返回过滤器要求的子目录

  [java]

  File file = new File("/home/colin");

  //有没有考虑过,java中不允许实现接口实例,但是在匿名内部类中却实现了接口,比如这个FileFilter接口

  //实际上如果查看编译后的代码(会发现编译后的代码中有一个class文件,这个class实现了这个接口,并重写了这个接口的方法)

  //所以这是一种虚拟实例化接口,或者理解为间接实例化接口。

  File[] childs = file.listFiles(new FileFilter() {

  @Override

  public boolean accept(File pathname) {

  return pathname.getName().startsWith(".");

  }

  });

  还有一个listFiles(FilenameFileter filter):FilenameFile用于检测指定文件是否包含在特定目录下

  其他API相对简单了,获取文件状态、创建删除文件

  RandomAccessFile随机读写文件

  File 实例只涉及到对文件的操作,java提供了可以对文件随机访问的操作,访问包括读和写操作,这种实现是基于指针的操作。

  两个构造方法:

  RandomAccessFile(File name,String model)

  RandomAccessFile(String name,String model)

  model指定的是对文件随机访问操作模式,有两种模式分别是只读模式和读写模式,"r"表示文件的访问是只读的,"rw"表示读和写模式。

  [java]

  RandomAccessFile file = new RandomAccessFile("/home/colin","rw");

  写数据:

  write(byte[] b):将指定自己数组b写到随机读写文件中,写到指针的位置

  write(byte[] b,int off,int len):指定了起始位置和长度

  write(int n):将n的低八位写到文件中去

  他还有写入特定特性的方法:writeBoolean(boolean b)、writeInt(int n)、writeDouble(double v)、writeChart(chart c)、writeCharts(String s)、writeByte(int n)、writeBytes(String s)、writeFloat(Float t)等

  读数据:

  int read():读取1byte(8位)放到int的低八位中,高24为为0。如果读到-1,说明读到了文件的末尾

  int read(byte[] b):最多读取b.length个字节到数组中,返回值为实际读取到的字节量

  int read(byte[] b,int off, int length):指定读取数组的起始位置和读取长度

  相应的还有读取特定类型数据的read

  readBoolean()、readFloat()等等,特别还有一个readLine()读取当前位置的一行

  这些都是从当前指针位置开始读取的

  释放关联的资源:void close()

  获取当前RandomAccessFile的指针:long getFilePoint(),以字节为单位,比如如果一个Int是4位

  移动当前指针位置:void seek(long pos)

  跳过n个字节:int sikpBytes(int n):返回跳过的实际字节数,n为负数不跳过任何字节

  [java]

  RandomAccessFile file = null;

  try {

  file = new RandomAccessFile("/home/colin/test.txt","rw");

  //byte[] b = "this is sample RandomAccessFile".getBytes();

  //file.read(b);

  byte[] b = new byte[10];

  while(file.read(b) >0){

  System.out.println(new String(b));

  System.out.println(file.getFilePointer()); //获取文件指针

  file.skipBytes(1); //每次读取跳过一个字节

  }

  } catch (FileNotFoundException e) {

  e.printStackTrace();

  }finally{

  if(file != null)

  file.close();

  }

  基本IO

  输入是指从外界进入程序方向,即当我们需要读取数据的时候,使用输入。

  输出是指从程序发送到外界方向,通常我们需要写出数据到外界,所以输出是用来写数据的。

  流的分类

  根据单位:字节流(8bit,图片视频等)和字符流(16bit,文本)

  根据角色:节点流(直接作用在文本上的流,直接与特定的地方(磁盘、内存)相连)和处理流(在节点流外层的流,是对一个已经存在流的连接和封装,在所封装的流的功能上实现数据的读写)

  java中40多种流都是从4个基类派生出来的

  字节流 字符流

  输入:InputStream Reader

  输出:OutputStream Writer

  InputStream和OutputStream

  二者都是字节流的抽象基类,定义了基本的read和write方法,read()、read(byte[] a,int off,int length)、read(byte[] b)、write(int b)、write(byte[] b)、write(byte[] b,int off ,int len)

  Reader和Writer

  reader和writer都是字符流的抽象基类,定义了读取字符的read和write。read()、read(char[] cbuf)、read(char[] cbuf,int off, int len)、write(char c)、write(char[] cbuf)、cbuf(cbuf,int off ,int len)

  文件流

  文件字节流:

  FileOutputStream可以使用以下几种方法构造:

  FileOUtputStream(File file)

  FileOutputStream(String name)

  指定写入的文件,如果该文件存在的化会清除该文件上面的内容

  FileOutputStream(File file,boolean append)

  FileOutputStream(String name,boolean append)

  如果指定append参数为true,则如果写入的文件存在,是以追加的方式进行写入的

  FileInputStream可以使用以下方法构造:

  FileInputStream(File file)

  FileOutputStream(String name)

  文件字节流实现了inputStream和outputStream的基本read和write

  注意如果读取的时候返回-1,则说明读取到了EOF

  利用文件流实现文件的复制:

  [java]

  File file1 = new File("/home/colin/hello.py");

  File file2 = new File("/home/colin/hello2.py");

  FileInputStream input = null;

  FileOutputStream output = null;

  try {

  input = new FileInputStream(file1);

  output = new FileOutputStream(file2);

  byte[] b = new byte[10];

  int len = -1;

  while((len=input.read(b))!=-1){

  output.write(b, 0, len);

  }

  } catch (FileNotFoundException e) {

  e.printStackTrace();

  } catch (IOException e) {

  e.printStackTrace();

  }finally{

  try {

  //先关输入流,再关输出流

  bsp; if(inputput != null)

  inputput.close();

  if(output != null)

  output.close();

  } catch (IOException e) {

  e.printStackTrace();

  }

  }

  FileReader和FileWriter与FileInputStream和FileOutputStream使用情况一样。

  缓冲流

  BufferedInputStream原理:缓冲字节输入流,内部维护一个缓冲区,该流会尽可能一次性读取若干字节到缓冲区,然后逐一返回知道缓冲区中的数据被全部读取完毕,从而减少读取次数,提高读取效率,BIS就是一个处理流,该流提供了缓冲功能。他还提供了mark、reset和skip方法

  提供的构造方法:

  BufferedInputStream(InputStream input)

  BufferedInputStream(InputStream input,int size):size指定缓冲区大小

  BufferedOutputStream原理:缓冲输出流,内部维护一个缓冲区,每当向该流写入数据的时候,都会现将数据存储缓冲区中,当缓冲区已满的时候,缓冲流会将数据一次性全部写出。

  提供的构造方法:

  BufferedOutputStream(OutputStream out)

  BufferedOutputStream(OutputStream out,int size):指定缓冲区大小

  BufferedOutputStream只提供了write和flush()方法,flush()清空缓冲区,将缓冲区中的数据强制写入。

  利用缓冲流实现文件复制:

  [java]

  BufferedInputStream bis = null;

  BufferedOutputStream bos = null;

  try {

  bis = new BufferedInputStream(new FileInputStream(new File("/home/colin/hello.py")));

  bos = new BufferedOutputStream(new FileOutputStream(new File("/home/colin/hello3.py")));

  int len = -1;

  byte[] b = new byte[10];

  while((len=bis.read(b)) !=-1){

  bos.write(b, 0, len);

  }

  bos.flush();

  } catch (FileNotFoundException e) {

  e.printStackTrace();

  } catch (IOException e) {

  e.printStackTrace();

  }finally{

  try {

  //先关输入流,再关输出流

  if(bis != null)

  bis.close();

  if(bos != null)

  bos.close();

  } catch (IOException e) {

  e.printStackTrace();

  }

  }

  BufferedReader和BufferedWriter与BufferedInputStream和BufferedOutputStream实现原理是一样的,但是BufferedWriter提供了newLine(),写入换行符的方法

  对象流

  对象序列化:对象存在内存中,有时候需要将对象保存到磁盘上,或者将对象进行传输等这样的操作。这时候需要将对象转化为一个字节序列,这个过程称为对象序列化。

  对象反序列化:有时候需要将字节序列转化成为对应的对象,这个过程成为对象的反序列化。

  ObjectOutputStream:用来将对象进行序列化的输出流

  提供的构造方法:

  ObjectOutputStream()

  ObjectOutputStream(OutputStream out)

  使用其write方法,将对象转化成为一个字节序列后写出,write方法提供了诸如writeInt()等此类方法。

  ObjectInputStream:用来将对象反序列化

  提供的构造方法:

  ObjectInputstream()

  ObjectInputStream(InputStream input)

  使用其提供的readObject()方法,读取字节并转化为对应的对象

  这个整体思路是要对对象进行传递,需要将对象转换成为字节流以便传输,所以首先通过ObjectOutputStream进行写入,将对象写成字节进行传输。传递到目标位置后需要读取,这时候将传输的字节转换成为对象。

  如果使用ObjectOutputStream进行序列化写入,需要序列化对象实现Serializable接口,该接口并没有任何方法只是序列化标志。通常实现该接口需要给出一个serialVersionUID,表明该类版本,若不显示声明编译器也会经过计算给出一个serialVersionUID,但是不同编译器实现有所不同,所以如果想要跨平台,都应该显示声明版本号。当类的对象序列化到磁盘上面,之后随之需求改变,改变了类的属性,那么反序列化就会出现InvalidClassException,这样就会造成不兼容问题。但当serialVersionUID相同时,会将不一样的Field以type的预设值反序列化,可以避开不兼容问题

  transient关键词:当我们对对对象进行序列化后,得带的字节序列往往比较大,有时我们在对一个对象进行序列化时可以忽略某些不必要的属性,从而对序列化后得到的字节序列瘦身,可以将其声明为transient,这样这些属性在序列化时会被忽略。

  实例:

  [java]

  /*

  *构造Emp类,对其对象进行序列化与反序列化

  */

  public class Emp implements Serializable {

  private static final long serialVersionUID = 1L;

  private String name;

  private int age;

  private double salary;

  private transient String description; //使用transient修饰,在反序列化时输出null

  public Emp(String name,int age,double salary,String description){

  this.name = name;

  this.age = age;

  this.salary = salary;

  this.description = description;

  }

  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 double getSalary() {

  return salary;

  }

  public void setSalary(double salary) {

  this.salary = salary;

  }

  public String getDescription() {

  return description;

  }

  public void setDescription(String description) {

  this.description = description;

  }

  @Override

  public String toString() {

  return "Emp [name="+name+",age="+age+",salary="+salary+",description="+description+"]";

  }

  }

  /*

  * 将Emp对象序列化,并且存储

  */

  public static void testOos(){

  ObjectOutputStream oos = null;

  try {

  FileOutputStream fos = new FileOutputStream(new File("/home/colin/oos.obj"));

  oos = new ObjectOutputStream(fos);

  Emp emp = new Emp("colin", 23, 13000, "I want you!!!");

  oos.writeObject(emp);

  } catch (FileNotFoundException e) {

  e.printStackTrace();

  } catch (IOException e) {

  e.printStackTrace();

  }finally{

  try {

  if(oos != null)

  oos.close();

  } catch (IOException e) {

  e.printStackTrace();

  }

  }

  }

  /*

  * 将存储的Emp对象反序列输出

  */

  public static void testOis(){

  ObjectInputStream ois = null;

  try {

  FileInputStream fis = new FileInputStream(new File("/home/colin/oos.obj"));

  ois = new ObjectInputStream(fis);

  Emp emp = (Emp)ois.readObject();

  System.out.println(emp.getName()+","+emp.getAge()+","+emp.getSalary()+","+emp.getDescription());

  } catch (FileNotFoundException e) {

  e.printStackTrace();

  } catch (IOException e) {

  e.printStackTrace();

  } catch (ClassNotFoundException e) {

  e.printStackTrace();

  }

  }