IO流的概念与使用


1.字节流与字符流

在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据时要使用输入流读取数据,当程序要将一些数据保存起来时,就要使用输出流。
JAVA IO包中,流的操作主要有字节流和字符流两大类,这两类都有输入和输出操作。字节流的顶级父类是InputStream,和OutputStream。字符流的顶级父类是Reader和Writer.这两个体系有个规律,字节流的子类都是以Stream结尾的,而字符流的子类是以Reader或者Writer结尾的。

1.1字节流的使用

一、字节输出流OutputStream
OutputStream是字节输出流的最大父类,如果想使用这个类必须要使用该类的子类。如果操作文件一般使用FileOutputStream类,OutputStream类中主要的操作方法有下面几种:
	public void close() throws IOException
	public void flush() throws IOException
	public void write(byte[] b) throws IOException
	public void write(byte[] b,int off,int len) throws IOException
	public abstract void write(int b) throws IOException

此时使用FileOutputStream子类,构造方法如下:
public FileOutputStream(File file) throws FileNotFoundExcepton
public FileOutputStream(String path) throws FileNotFoundExcepton
操作时必须接受File类的实例,或指明输出的文件路径。

向文件中写入字符串示例代码:
public class Test {
	public static void main(String[] args) throws IOException {
		//第一部实例化一个File对象
		File f = new File("d:/test.txt");
		//通过子类实例化父类对象
		OutputStream os = new FileOutputStream(f);
		//进行写操作
		String str = "hello world";
		byte[] b = str.getBytes();
		os.write(b);
		//关闭资源
		os.close();
	}
}
运行结果会发现内容已经成功的写在了文件中。但是有个问题,多次运行之后会发现文件中始终只有一个hello world也就是说,写的操作每次都覆盖了之前的内容。
要想在文件末尾追加内容要用到下面的构造函数:
public FileOutputStream(String name, boolean append) throws FileNotFoundException
也就是说在实例化OutputStream时,改为
OutputStream os = new FileOutputStream(f, true);
这样就可以在文件末尾追加内容了。

二、字节输入流
当程序需要从文件中读取内容的时候就用到了输入流,与OutputStream一样,InputStream是个抽象类,必须依靠子类进行实例化,如果是读取文件,子类可以用FileInputStream, 常用方法如下:
	public int available() throws IOException       //可以取得输入文件的大小
	public void close() throws IOException          //关闭输入流
	public abstract int read() throws IOException   //读取内容,以数字的方式读取
	public int read(byte[] b) throws IOException    //将内容读到byte数组中,同时返回读入的个数
示例,从文件中读取内容:
public class Test {
	public static void main(String[] args) throws IOException {
		InputStream is = new FileInputStream("d:/abc/abc.txt");
		byte[] b = new byte[1024];
		int len = is.read(b);
		is.close();
		System.out.println(new String(b,0,len));
	}
}
程序运行结果为:
hello world

结合输入输出流复制mp3例子:
	public static void copyMp3() throws IOException{
		InputStream is = new FileInputStream("d:/1.mp3");   //定义输入流并绑定要拷贝的mp3
		OutputStream os = new FileOutputStream("d:/2.mp3"); //定义输出流并制定拷贝到的路径和文件名称
		byte[] b = new byte[1024];                          //定义缓冲数组大小,一般是1024的整数倍
		int len = 0;
		while((len = is.read(b))!=-1){
			os.write(b, 0, len);                        //将读取的数据直接写入到目标文件
		}
		is.close();                                         //关闭资源
		os.close();
	}


1.2字符流的使用

在java中一个字符等于两个字节,java提供了Reader和Writer两个专门操作字符流的类。需要明确的一点是,字符流只能操作纯文本文件。
如果想从一个文本文件读取内容可以用FileReader类,例如:
	public static void read() throws IOException{
                Reader reader = new FileReader("d:/test.txt");
                char[] c = new char[1024];
                int len = 0;
                int count = 0;
                while((len = reader.read())!=-1){
                        c[count] = (char) len;
                        count++;
                }
                System.out.println(new String(c));
                reader.close();
	}

但是这样读取效率比较慢,可以自己定义一个缓冲区,每次让读取出的数据存在缓冲区内,然后再从缓冲区内取数据,例:
	public static void read() throws IOException{
                Reader reader = new FileReader("d:/test.txt");
                char[] b = new char[1024];
                int len = reader.read(b);
                System.out.println(new String(b,0,len));
                reader.close();
	}

向文件中写入数据可以使用FileWriter类:
	public static void write() throws IOException{
                Writer writer = new FileWriter("d:/test.txt");
                String str = "java";
                char[] c = str.toCharArray();
                writer.write(c);
                writer.close();
	}

程序运行之后发现字符串成功的写入到文件中去了。

BufferedReader和BufferedWriter

BufferedReader类用于从缓冲区中读取数据,所有输入字节数据都将放在缓冲区中,此类还增加了readLine()方法,实现了一次读取一行紫字符的功能。例如:
	public static void read() throws IOException{
		Reader r = new FileReader("d:/test.txt");
		BufferedReader br = new BufferedReader(r);
		String str = null;
		int count = 0;
		while((str = br.readLine())!=null){
			count++;
			System.out.println("第"+count+"行内容是:"+str);
		}r.close;br.close;
	}
上面的例子就使用了BufferedReader类的readLine方法
输出内容为:
第1行内容是:abc
第2行内容是:def
第3行内容是:ghi
第4行内容是:xyz

BufferedRead和BufferedWriter结合使用实现的文件复制功能:
	public static void writeMethod2() throws IOException{
		Reader r = new FileReader("d:/test.txt");
		Writer w = new FileWriter("d:/test0.txt");
		BufferedReader br = new BufferedReader(r);
		BufferedWriter bw = new BufferedWriter(w);
		String str = null;
		int count = 0;
		while((str = br.readLine())!=null){
			count++;
			bw.write(str);
			bw.flush();
			System.out.println("第"+count+"行内容是:"+str);
		}
		r.close();
		w.close();
		br.close();
		bw.close();
	}

BufferedRead和BufferedWriter由于使用了缓存,所以用它们读写文件效率非常高。

2.转换流

整个IO包分为字节流和字符流,但是除了这两个流之外还有一组字节流-字符流的转换类。
OutputStreamWriter:是Writer的子类,将输入的字节流变成字符流,即将一个字节流输出对象变成字符流输出对象。
InoutStreamReader:是Reader的子类,将输入的字节流变成字符流,即将一个字节流输入对象变成字符流输入对象。
例如,向一个文件写数据使用转换流的方式为:
	public static void test() throws IOException{
		OutputStream os = new FileOutputStream("d:/test.txt");
		Writer w = new OutputStreamWriter(os);
		String str = "hello world";
		w.write(str);
		os.close();
		w.close();
	}

实现了从字节流到字符流的转换。
从一个文件中读取信息使用转换流的方式为:
	public static void test() throws IOException{
		InputStream is = new FileInputStream("d:/test.txt");
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		String str = null;
		while((str = br.readLine())!=null){
			System.out.println(str);
		}
	}

实现了从字节输入流到字符输入流的转换。

3.流的选择

当流的对象很多不知道该用哪个的时候,一般通过两个来明确:
1. 明确源和目的
源就是输入流:InputStream, Reader
目的是输出流:OutputStream, Writer
2.操作的数据是否为纯文本
是:字符流
否:字节流

当体系明确后在明确要使用哪个具体的对象,通过设备区分:
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台

Reader体系中可以操作文件的对象是FileReader
Writer体系中可以操作文件的是FileWriter
如需提高效率,使用加入了缓冲区的BufferedReader
同理还有BufferedWriter

分析例子:将键盘录入信息输入一个文件
源:InputStream Reader
是纯文本:Reader
键盘录入对应的对象是System.in需要把字节流转换为字符流,所以要用到转换流:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

4.Properties文件

j ava中的.properties文件是一种配置文件,主要用于表达配置信息,文件类型为*.properties,格式为文本文件,文件的内容是格式是"键=值"的格式。
Properties类的重要方法
Properties 类存在于胞 Java.util 中,该类继承自 Hashtable
1. getProperty ( String  key) ,   用指定的键在此属性列表中搜索属性。也就是通过参数 key ,得到 key 所对应的 value。
2. load ( InputStream  inStream) ,从输入流中读取属性列表(key和value)。通过对指定的文件进行装载来获取该文件中的所   有键 - 值对。以供 getProperty ( String  key) 来搜索。
3. setProperty ( String  key, String  value) ,调用 Hashtable 的方法 put 。他通过调用基类的put方法来设置 键 - 值对。 
4. store ( OutputStream  out, String  comments) ,   以适合使用 load 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。与 load 方法相反,该方法将键 - 值对写入到指定的文件中去。
现在假设在src目录下有个名字为test.properties的文件,内容为:
key1=value1
key2=value2
读取配置文件的程序为:
	public static void test() throws IOException{
		Properties pro = new Properties();
		InputStream is = new FileInputStream("src/test.properties");
		pro.load(is);
		System.out.println("key1对应的值为:"+pro.getProperty("key1"));
		System.out.println("key2对应的值为:"+pro.getProperty("key2"));
		is.close();
	}
运行结果为:
key1对应的值为:value1
key2对应的值为:value2

如果想改变其中某个key值所对应的属性可以这样:
	public static void test() throws IOException{
		Properties pro = new Properties();
		InputStream is = new FileInputStream("src/test.properties");
		pro.load(is);
		pro.setProperty("key1", "hello world");
		System.out.println("key1对应的值为:"+pro.getProperty("key1"));
		System.out.println("key2对应的值为:"+pro.getProperty("key2"));
		is.close();
	}
这样程序运行结果为:
key1对应的值为:hello world
key2对应的值为:value2
达到了改变某个key所对应的值。


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值