黑马程序员__IO

黑马程序员—IO流

------- android培训java培训、期待与您交流! -----------------

1.File类

  File类是用来将文件或文件夹封装成对象的类,方便对文件与文件夹的属性信息进行操作。如果需要在程序中操作文件和目录,都是可以通过File类来完成。File不能访问文件内容本身。如果需要访问文件内容本身,则需要使用IO流。

  File类的常用操作方法:

 

 

import java.io.*;
public class FileMethod
{
	public static void main(String[] args)
		throws IOException
	{
		// 创建一个File对象
		File file = new File("D;\\a.txt"); 
		// 获取文件名
		System.out.println(file.getName());
		// 获取相对路径的父路径
		System.out.println(file.getParent());
		// 获取绝对路径
		System.out.println(file.getAbsoluteFile());
		// 获取上一级路径
		System.out.println(file.getAbsoluteFile().getParent());
		// 在当前路径下创建一个临时文件
		File tmpFile = File.createTempFile("aaa", ".txt", file);
		// 指定当JVM退出时删除该文件
		tmpFile.deleteOnExit();
		// 以系统当前时间作为新文件名来创建新文件
		File newFile = new File(System.currentTimeMillis() + "");
		System.out.println("newFile对象是否存在:" + newFile.exists());
		// 以指定newFile对象来创建一个文件
		newFile.createNewFile();
		// 以newFile对象来创建一个目录,因为newFile已经存在,
		// 所以下面方法返回false,即无法创建该目录
		newFile.mkdir();
		// 使用list()方法来列出当前路径下的所有文件和路径
		String[] fileList = file.list();
		System.out.println("====当前路径下所有文件和路径如下====");
		for (String fileName : fileList)
		{
			System.out.println(fileName);
		}
		// listRoots()静态方法列出所有的磁盘根路径。
		File[] roots = File.listRoots();
		System.out.println("====系统所有根路径如下====");
		for (File root : roots)
		{
			System.out.println(root);
		}
	}
}

 

//列出指定目录下的所有文件
	public static void showDir(File dir)
	{
		System.out.println(dir);
		//列出所有文件及目录
		File[] files=dir.listFiles();
		for(int i=0;i<files.length;i++)
		{
			if(files[i].isDirectory())
				//递归调用
				showDir(files[i]);
			else
				System.out.println(files[i]);
		}
	}


  总结:

      (1)File既可以表示一个文件,也可以表示一个目录;

      (2)File类的对象是与平台无关的;

      (3)File类针对文件或文件目录,只能进行新建、删除等属性操作。如果涉及访问文件内容,File是无能为力的,只能使用IO流下提供的相应的IO流来实现;

      (4)常把File类的对象作为形参传递给相应的IO流的构造函数中。

2.IO流

  2.1 流的分类

     (1)按照流的流向的不同分为输入流和输出流:

         输入流:只能从中读取数据,而不能向其写入数据。主要由InputStream和Reader作为基类。

         输出流:只能向其写入数据,而不能从中读取数据。主要由OutputStream和Writer作为基类。

    (2)按照流中数据单位的不同分为字节流和字符流:

        字节流:数据单位为字节。主要由InputStream和OutputStream作为基类。

        字符流:数据单位为字符。主要由Reader和Writer作为基类。

 2.2 字节流和字符流的相关操作

    InputStream和Reader是所有输入流的抽象基类,本身并不能创建实例来执行输入,但它们将成为所有输入流的模板,所有它们的方法是所有输入流都可使用的方法。

    OutputStream和Writer与之相似。

    代码示例:

    

import java.io.*;
//字节流来实现文件的复制
public class FileOutputStreamTest
{
	public static void main(String[] args)
	{
		// 创建字节输入流和字节输出流
		FileInputStream fis=null;
		FileOutputStream fos=null;
		try
		{
			fis = new FileInputStream("Test.java"); 
			fos = new FileOutputStream("newFile.txt");
			byte[] bbuf = new byte[32];
			int hasRead = 0;
			// 循环从输入流中取出数据
			while ((hasRead = fis.read(bbuf)) > 0 )
			{
				// 每读取一次,即写入文件输出流,读了多少,就写多少。
				fos.write(bbuf , 0 , hasRead);
			}
		}
		catch (IOException ioe)
		{
			throw new RuntimeException("读写失败!");
		}
		finally
		{
			if(fis!=null)
				try {
					fis.close();
				} catch (IOException e) {
					

				}
			if(fos!=null)
				try {
					fos.close();
				} catch (IOException e) {
					throw new RuntimeException("关闭输出流失败");
				}
		}
	}
}


  字符流:

 

import java.io.*;
public class FileReaderTest
{
	public static void main(String[] args)
	{
		// 创建字符输入流
		FileReader fr=null;
		try
		{	
			fr= new FileReader("FileReaderTest.java");
			// 创建字符数组
			char[] cbuf = new char[32];
			// 用于保存实际读取的字符数
			int hasRead = 0;
			// 循环读取
			while ((hasRead = fr.read(cbuf)) > 0 )
			{
				// 将字符数组转换成字符串
				System.out.print(new String(cbuf , 0 , hasRead));
			}
		}
		catch (IOException ex)
		{
			throw new RuntimeException("读取失败!");
		}
		finally
		{
			if(fr!=null)
				try {
					fr.close();
				} catch (IOException e) {
					throw new RuntimeException("关闭输入流失败!");
				}
		}
	}
}


 

import java.io.*;
public class FileWriterTest
{
	public static void main(String[] args)
	{
		FileWriter fw=null;
		try
		{	
			fw= new FileWriter("text.txt");
			fw.write("helloworld!\r\n");
		}
		catch (IOException ioe)
		{
			throw new RuntimeException("写入失败!");
		}
		finally
		{
			if(fw!=null)
				try {
					fw.close();
				} catch (IOException e) {
					throw new RuntimeException("关闭输出流失败!");

				}
		}
	}
}

  字符流的缓冲区:对应类--BufferedWriter和BufferedReader

    缓冲区的出现是为了提高流的操作效率,所以在创建缓冲区之前,必须要有流对象。

    BufferedWriter:字符流写入缓冲区,该缓冲区提供了一个跨平台的换行符:newLine()。

    BufferedReader:字符流读取缓冲区,该缓冲区提供了一个读取一行的方法:readLine(),以便于对文本数据的获取,当返回null时表示读到文件末尾。

    示例:通过缓冲区复制一个.java文件。

   

import java.io.*;


public class CopyTextByBuf {
	public static void main(String[] args) {
		//创建流对象
		BufferedReader bufr=null;
		BufferedWriter bufw=null;
		try {
			bufr=new BufferedReader(new FileReader("Person.java"));
			bufw=new BufferedWriter(new FileWriter("copy.txt"));
			String line=null;
			//循环读取
			while((line=bufr.readLine())!=null)
			{
				//将读取的数据写入流中
				bufw.write(line);
				//换行
				bufw.newLine();
				//刷新
				bufw.flush();
			}
		} 
		catch (IOException e) {
			throw new RuntimeException("读写失败!");
		}
		finally
		{
			if(bufr!=null)
				try {
					bufr.close();
				} catch (IOException e) {
					throw new RuntimeException("关闭读取流失败!");
				}
			if(bufw!=null)
				try {
					bufw.close();
				} catch (IOException e) {
					throw new RuntimeException("关闭写入流失败!");
				}
		}
		
	}

}


 2.3 转换流

    IO体系中提供了两个转换流,用于实现将字节流转换为字符流,其中:

    InputStreamReader将字节输入流转换为字符输入流;

    OutputStreamWriter将字节输出流转换为字符输出流。

    代码示例:

   

import java.io.*;
public class KeyinTest
{
	public static void main(String[] args) 
	{
		InputStreamReader reader=null;
		BufferedReader br=null;
		try
		{
			// 将Sytem.in对象转换成Reader对象
			 reader= new InputStreamReader(System.in);
			//将普通Reader包装成BufferedReader
			 br= new BufferedReader(reader);
			 String buffer = null;
			//采用循环方式来一行一行的读取
			while ((buffer = br.readLine()) != null)
			{
				//如果读取的字符串为"exit",程序退出
				if (buffer.equals("exit"))
				{
					System.exit(1);
				}
				//打印读取的内容
				System.out.println("输入内容为:" + buffer);
			}
		}
		catch (IOException ioe)
		{
			throw new RuntimeException("读写失败!");
		}
		finally
		{
			if(br!=null)
				try {
					br.close();
				} catch (IOException e) {
					throw new RuntimeException("关闭流失败!");
				}
		}
	}
}


 2.4 打印流:PrintWriter和PrintStream。

     该流提供了打印方法,可以将各种数据类型的数据都原样打印。

     (1)字节打印流:PrintStream

         此类的构造函数可以接收的参数类型有:File、String、OutputStream。

     (2)字符打印流:PrintWriter

         此类的构造函数可以接收的参数类型有:File、String、OutputStream、Writer。

   代码示例:

  

//接收键盘输入的字符串将其转换为大写在控制台上输出
import java.io.*;
public class PrintWriterTest {
	public static void main(String[] args) {
		//创建输入输出流对象
		BufferedReader bufr=null;
		PrintWriter pw=null;
		try {
			//接收键盘收入
			bufr=new BufferedReader(new InputStreamReader(System.in));
			pw=new PrintWriter(System.out,true);
			String line=null;
			while((line=bufr.readLine())!=null)
			{
				if(line.equals("over"))
					break;
				pw.println(line.toUpperCase());
			}
		}
		catch (IOException e) {
			throw new RuntimeException("读写失败!");
		}
		finally
		{
			if(bufr!=null)
				try {
					bufr.close();
				} catch (IOException e) {
					throw new RuntimeException("关闭流失败!");
				}
			if(pw!=null)
				pw.close();
		}
	}

}


 

2.5 对象的序列化:对象流 ObjectInputStream和ObjectOutputStream

    对象的序列化是指将内存中的Java对象转换成与平台无关的二进制流,从而把这种二进制流持久地保存在硬盘上。如果需要让某个对象实现序列化,则必须让其实现Serializable接口。

    使用对象流来实现序列化:

  

//人类
import java.io.Serializable;
class Person implements Serializable 
{
	private String name;
	private int age;
	public Person() {
		super();
	}
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = 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 String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
}


 

public static void writeObj()
	{
		//创建写入对象流
		ObjectOutputStream oos=null;
		try 
		{
			oos=new ObjectOutputStream(new FileOutputStream("person.obj"));
			//向文件中写入对象信息
			oos.writeObject(new Person("张三",20));
		} 
		catch (IOException e) {
			throw new RuntimeException("创建文件失败!");
		}
		finally
		{
			if (oos!=null)
				try {
					oos.close();
				} catch (IOException e) {
					throw new RuntimeException("关闭流发生异常!");
				}
		}
	}
	public static void readObj()
	{
		//创建读取对象流
		ObjectInputStream ois=null;
		try 
		{
			ois=new ObjectInputStream(new FileInputStream("person.obj"));
			//读取文件中的对象信息
			Person p=(Person)ois.readObject();
		} 
		catch (Exception e) {
			throw new RuntimeException("创建文件失败!");
		}
		finally
		{
			if (ois!=null)
				try {
					ois.close();
				} catch (IOException e) {
					throw new RuntimeException("关闭流发生异常!");
				}
		}
	}


  注意:

   (1)静态成员是不能被序列化的;

   (2)如果对非静态的成员不想被序列化的话,可以加上transient修饰。

 2.5 RandomAccessFile:随机访问文件,其自身具备读写的方法。

     该类不属于IO体系的子类,其直接继承Object,但它是IO包中的成员,因为它具备读和写的功能。其内部封装了一个数组,而且可以通过指针对数组的元素进行操作,并且可以通过getFilePointer()来获取指针的位置,同时可以通过seek改变指针的位置。其完成读写的原理就是内部封装了字节输入流和输出流,通过构造函数可以看出此类只能操作硬盘上的文件,而且操作还有规定模式:如只读(r)、读写(rw)等等。如果模式为只读,操作文件时不会创建文件而是会读取一个已经存在的文件,若文件不存在则会出现异常;如果模式为读写,操作文件时,若文件不存在会自动创建文件,若文件存在不会覆盖。

 

public class RandomAccessFileTest
	{
		public static void main(String[] args) 
		{
			RandomAccessFile raf=null;
			try
			{
				raf =  new RandomAccessFile("FileTest.java" , "r");
				// 获取RandomAccessFile对象文件指针的位置,初始位置是0
				System.out.println("File的文件指针的初始位置:" + raf.getFilePointer());
				// 移动raf的文件记录指针的位置
				raf.seek(300);
				byte[] bbuf = new byte[1024];
				// 用于保存实际读取的字节数
				int hasRead = 0;
				// 循环读取
				while ((hasRead = raf.read(bbuf)) > 0 )
				{
					// 将读取的字节数组转换成字符串输入!
					System.out.print(new String(bbuf , 0 , hasRead ));
				}
			}
			catch (IOException ex)
			{
				throw new RuntimeException("操作失败!");
			}
			finally
			{
				if(raf!=null)
					try {
						raf.close();
					} catch (IOException e) {
						throw new RuntimeException("操作失败!");
					}
			}
		}
	}

  2.6 数据流:DataInputStream和DataOutputStream

   此流是用来操作基本数据类型的。

 

 

public static void readData()
	{
		//创建数据读取流对象
		DataInputStream dis=null;
		DataOutputStream dos=null;
		try 
		{
			dis=new DataInputStream(new FileInputStream("data.txt"));
			dos=new DataOutputStream(new FileOutputStream("data.txt"));
			//写入数据
			dos.writeBoolean(true);
			//读取数据
			boolean b=dis.readBoolean();
			dos.writeDouble(2.2d);
			double d=dis.readDouble();
			dos.writeFloat(1.1f);
			float f=dis.readFloat();
			dos.writeInt(10);
			int i=dis.readInt();
			//使用writeUTF写入的数据必须是使用与之对应的读取方法才能读出来
			dos.writeUTF("大家好!");
			String s=dis.readUTF();
		}
		catch (IOException e) {
			throw new RuntimeException("操作失败!");
		}
		finally
		{
			if(dos!=null)
				try {
					dos.close();
				} catch (IOException e) {
					throw new RuntimeException("操作失败!");
				}
			if(dis!=null)
				try {
					dis.close();
				} catch (IOException e) {
					throw new RuntimeException("操作失败!");
				}
		}
		
		
	}

 2.7 数组流:用流的思想来操作数组

    字节数组流:ByteArrayInputStream和ByteArrayOutputStram

             字符数组流:CharArrayInputStream和CharArrayOutputStram

    字符串数组流:StringArrayInputStream和StringArrayOutputStram

     以字节数组流为例:

               ByteArrayInputStream:在构造的时候需要接收数据源,而且数据源是一个字节数组。

    ByteArrayOutputStram:在构造的时候不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组,这就是目的地。

    注意:因为这两个流对象都是操作的数组并没有使用系统资源,所以,不用进行资源的关闭,也没有异常的发生。

public class ByteArrayTest {
 	public static void main(String[] args) {
		//数据源
		ByteArrayInputStream bis=new ByteArrayInputStream("abcdefg".getBytes());
		//数据目的
		ByteArrayOutputStream bos=new ByteArrayOutputStream();
		int by=0;
		while((by=bis.read())!=-1)
		{
			bos.write(by);
		}
		System.out.println(bos.toString());
	}

}


3. NIO

  从JDK1.4开始,Java提供了一系列改进的输入、输出处理的新功能,这些功能被统称为新IO(NIO)。

  新IO中的一些常用的类

  (1)Buffer:表示缓冲,可以理解为一个数组容器。

      Buffer中有三个重要的概念:容量(capacity),界限(limit)和位置(position)

      容量:表示该缓冲区的最大数据容量;

      界限:表示第一个不应该被读出或者写入的缓冲区位置索引,也就是说,位于界限处的数据既不可以被读,也不可以被写。

      位置:用于指明下一个可以被读出的或者写入的缓冲区位置索引。

  代码示例:

     

import java.nio.*;
public class BufferTest
{
	public static void main(String[] args)
	{
		// 创建Buffer
		CharBuffer buff = CharBuffer.allocate(8);  
		System.out.println("capacity: "	+ buff.capacity());
		System.out.println("limit: " + buff.limit());
		System.out.println("position: " + buff.position());
		// 放入元素
		buff.put('a');
		buff.put('b');
		buff.put('c');      
		System.out.println("加入三个元素后,position = "+ buff.position());
		// 调用flip()方法,使limit回到原位置处
		buff.flip();	  
		System.out.println("执行flip()后,limit = " + buff.limit());
		System.out.println("position = " + buff.position());
		// 取出第一个元素
		System.out.println("第一个元素(position=0):" + buff.get());  // 
		System.out.println("取出一个元素后,position = " 
			+ buff.position());
		// 调用clear方法
		buff.clear();     
		System.out.println("执行clear()后,limit = " + buff.limit());	
		System.out.println("执行clear()后,position = "+ buff.position());
		System.out.println("执行clear()后,缓冲区内容并没有被清除:"+ "第三个元素为:" +  buff.get(2));    // ⑥
		System.out.println("执行绝对读取后,position = "+ buff.position());
	}
}


 

 (2)Channel:表示通道。Channel是对传统的IO流系统的模拟,在新IO系统中所有的数据都需要通过通道传输;Channel与传统的IO的最大区别在于它提供了一个map方法,通过map可以直接将一块数据映射到内存中,如果说传统IO是面向流的处理,那么新IO就是面向块的处理。

    Channel中最常用的3个方法是map()、read()、write()。

     map()方法用于将Channel对应的部分或全部数据映射成ByteBuffer;而read()和write()方法用于从Buffer中读取数据和向Buffer中写入数据。

     代码示例:

     将FileChannel中的全部数据映射成ByteBuffer:

    

import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
public class FileChannelTest
{
	public static void main(String[] args)
	{
		File f = new File("FileChannelTest.java");
		try(
			// 创建FileInputStream,以该文件输入流创建FileChannel
			FileChannel inChannel = new FileInputStream(f).getChannel();
			// 以文件输出流创建FileBuffer,用以控制输出
			FileChannel outChannel = new FileOutputStream("a.txt").getChannel())
		{
			// 将FileChannel里的全部数据映射成ByteBuffer
			MappedByteBuffer buffer = inChannel.map(FileChannel
				.MapMode.READ_ONLY , 0 , f.length());   
			// 使用GBK的字符集来创建解码器
			Charset charset = Charset.forName("GBK");
			// 直接将buffer里的数据全部输出
			outChannel.write(buffer);    
			// 再次调用buffer的clear()方法,复原limit、position的位置
			buffer.clear();
			// 创建解码器(CharsetDecoder)对象
			CharsetDecoder decoder = charset.newDecoder();
			// 使用解码器将ByteBuffer转换成CharBuffer
			CharBuffer charBuffer =  decoder.decode(buffer);
			// CharBuffer的toString方法可以获取对应的字符串
			System.out.println(charBuffer);
		}
		catch (IOException ex)
		{
			ex.printStackTrace();
		}
	}
}


 

4.字符编码

  编码(Encode):把字符序列转换成二进制序列。

  解码(Decode):将二进制序列转换为能看懂的字符序列。

  常用编码:

  ASCII:美国标准信息交换码。用一个字节的7位可以表示。

  ISO8859-1:拉丁码表或欧洲码表。用一个字节的8位表示。

  GB2312:中国的中文编码表。 
  GBK:中国的中文编码表升级,融合了更多的中文文字符号。 
  Unicode:国际标准码,融合了多种文字。所有文字都用两个字节来表示,Java语言使用的就是unicode。 
  UTF-8:最多用三个字节来表示一个字符。

总结:

  IO中的四个抽象基类:

  InputStream   OutputStream

  Reader        Writer

  文件流:

  FileInputStream  FileOutputStream

  FileReader      FileWriter

  缓冲处理流

  BufferedInputStream  BufferedOutputStream

  BufferedReader      BufferedWriter

  转换流

  InputStreamReader

  OutputStreamWriter

  标准输入输出流

  System.in

  System.out

注意:

 (1)从硬盘上读入一个文件,要求此文件一定得存在。若不存在,则会发生FileNotFoundException的异常。

 (2)从程序中输出一个文件到硬盘,此文件可以不存在。若不存在,就创建一个;若存在,则会将存在的文件覆盖。

 (3)真正开发时,应当使用缓冲流来提供效率。

 (4)注意要关闭相应的流,以释放资源。

 

------- android培训java培训、期待与您交流! ----------
      

 


 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值