Java基础系列八之IO流

一、流的概念
       流(stream)的概念源于UNIX中管道(pipe)的概念。在UNIX中,管道是一条不间断的字节流,用来实现程序或进程间的通信,或读写外围设备、外部文件等。
       一个流,必有源端和目的端,它们可以是计算机内存的某些区域,也可以是磁盘文件,甚至可以是Internet上的某个URL。
        流的方向是重要的,根据流的方向,流可分为两类:输入流和输出流。用户可以从输入流中读取信息,但不能写它。相反,对输出流,只能往输入流写,而不能它
       实际上,流的源端和目的端可简单地看成是字节的生产者和消费者,对输入流,可不必关心它的源端是什么,只要简单地从流中读数据,而对输出流,也可不知道它的目的端,只是简单地往流中写数据。 
       形象的比喻——水流 ,文件======程序 ,文件和程序之间连接一个管道,水流就在之间形成了,自然也就出现了方向:可以流进,也可以流出.便于理解,这么定义流: 流就是一个管道里面有流水,这个管道连接了文件和程序。
二、流的分类
  1. java.io包中的流对应两种流,一种流直接从指定的位置(如磁盘文件或内存区域)读或写,这种流称为结点流(node stream),其它的流则称为过滤器(filters)。过滤器输入流往往是以其它输入流作为它的输入源,经过过滤或处理后以新的输入流形式提供给用户,过滤器输出流的原理也类似。

  2. Java中的流,可以从不同的角度进行分类。

    按照数据据流的方向不同可以分为:输入流和输出流。

    按照处理数据单位不同可以分为:字节流和字符流。

    按照实现功能不同可以分为:节点流和处理流。

     

    输出流:

     

    输入流:

    因此输入和输出都是从程序的角度来说的。

    字节流:一次读入或读出是8位二进制。

    字符流:一次读入或读出是16位二进制。

    字节流和字符流的原理是相同的,只不过处理的单位不同而已。后缀为Stream是字节流,而后缀为ReaderWriter是字符流。

     

    节点流:直接与数据源相连,读入或读出。

    直接使用节点流,读写不方便,为了更快的读写文件,才有了处理流。

    处理流:与节点流一块使用,在节点流的基础上,再套接一层,套接在节点流上的就是处理流。

    Jdk提供的流继承了四大类:InputStream(字节输入流)OutputStream(字节输出流),Reader(字符输入流),Writer(字符输出流)。

    以下是javaio中常用的流。

     

    字节输入流:

    字节输出流:

    字符输入流:

    字符输出流:

    简单介绍其上图:

    对文件进行操作:

  3. FileInputStream(字节输入流)

  4. FileOutputStream(字节输出流)

  5. FileReader(字符输入流)

  6. FileWriter(字符输出流)

    对管道进行操作:PipedInputStream(字节输入流),PipedOutStream(字节输出流),PipedReader(字符输入流),PipedWriter(字符输出流)

    PipedInputStream的一个实例要和PipedOutputStream的一个实例共同使用,共同完成管道的读取写入操作。主要用于线程操作。

    字节/字符数组:ByteArrayInputStreamByteArrayOutputStreamCharArrayReaderCharArrayWriter是在内存中开辟了一个字节或字符数组。

    Buffered缓冲流::BufferedInputStreamBufferedOutputStreamBufferedReader,BufferedWriter,是带缓冲区的处理流,缓冲区的主要目的是:避免每次和硬盘打交道,提高数据访问的效率。

    转化流:InputStreamReader/OutputStreamWriter,把字节转化成字符。

    数据流:DataInputStreamDataOutputStream

    package io;
    
    import java.io.BufferedWriter;
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class Demo13 {
    	public static void main(String[] args) throws IOException {
    		BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("bw.txt"));
    		bufferedWriter.write("hello");
    		bufferedWriter.newLine();
    		bufferedWriter.write("world");
    		// 刷新流
    		bufferedWriter.flush();
    		// 关闭资源
    		bufferedWriter.close();
    	}
    }
    

    因为平时若是我们输出一个8个字节的long类型或4个字节的float类型,那怎么办呢?可以一个字节一个字节输出,也可以把转换成字符串输出,但是这样转换费时间,若是直接输出该多好啊,因此这个数据流就解决了我们输出数据类型的困难。数据流可以直接输出float类型或long类型,提高了数据读写的效率。

    打印流:printStreamprintWriter,一般是打印到控制台,可以进行控制打印的地方。

    对象流:ObjectInputStreamObjectOutputStream,把封装的对象直接输出,而不是一个个在转换成字符串再输出。

    序列化流:SequenceInputStream

    对象序列化:把对象直接转换成二进制,写入介质中。

    使用对象流需要实现Serializable接口,否则会报错。而若用transient关键字修饰成员变量,不写入该成员变量,若是引用类型的成员变量为null,值类型的成员变量为0.    三、流的概念和作用

    1. Java的常用输入、输出流
    java.io包中的stream类根据它们操作对象的类型是字符还是字节可分为两大类: 字符流和字节流。
     
    • Java的字节流
    InputStream是所有字节输入流的祖先,而OutputStream是所有字节输出流的祖先。
    • Java的字符流
    Reader是所有读取字符串输入流的祖先,而writer是所有输出字符串的祖先。
    结合开始所说的输入/输出流 ,出现了个一小框架。

                         字节流                         字符流
    输入流        InputStream               Reader
    输出流        OutputStream            Writer

    流的概念和作用

    学习Java IO,不得不提到的就是JavaIO流。

    流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。

    IO流的分类

    根据处理数据类型的不同分为:字符流和字节流

    根据数据流向不同分为:输入流和输出流

    字符流和字节流

    字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。字节流和字符流的区别:

    (1)读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。

    (2)处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。

    (3)字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的;而字符流在操作的时候下后是会用到缓冲区的,是通过缓冲区来操作文件,我们将在下面验证这一点。

    结论:优先选用字节流。首先因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。但是字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。


一次读取一个字节数组的方式要比一次读取一个字节的方式高效.

 一次读取一个字节数组,相当于构造一个缓冲区,有没有比一次读取一个字节数组还要高效的流?  字节缓冲流

代码示例
public class FileInputStreamDemo {

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

		// 复制操作:将e盘下的abc.mp4复制到当前项目下,输出copy.mp4
		// 封装源文件
		FileInputStream fis = new FileInputStream("e://abc.mp4");
		// 封装目的地文件
		FileOutputStream fos = new FileOutputStream("copy.mp4");

		// 读写操作:一次读取字节数组
		byte[] bys = new byte[1024];
		int len = 0;
		while ((len = fis.read(bys)) != -1) {
			// 边读边写
			fos.write(bys, 0, len);
		}

		// 释放资源
		fis.close();
		fos.close();
	}
}
计算机如何存储中文的?
  当前平台默认编码集 :GBK 一个中文两个字节
  第一个字节:一定是负数

  第二个字节:一般是负数,也可能是正数。

代码示例

package io;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;

public class Demo2 {

	public static void main(String[] args) throws UnsupportedEncodingException {
		// TODO Auto-generated method stub
		String string = "我爱你中国";
		// 转成字节数组
		byte[] bs = string.getBytes("gbk");
		System.out.println(bs);
		// 转成字符串的形式
		System.out.println(Arrays.toString(bs));
	}

}
 字节缓冲输入流
   public BufferedInputStream(InputStream in):默认缓冲区大小,构造缓冲输入流对象
   public BufferedInputStream(InputStream in,int size):指定缓冲区大小,构造缓冲输入流对象 
   public int read()
   public int read(byte[] b,int off,int len)
 在使用缓冲输入流的时候,

  两种方式读取(一次读取一个字节/一次读取一个字节数组),只能用一种方式,否则,会出现错误!

代码示例

package io;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.sql.Time;

public class Demo3 {
	private static BufferedInputStream bufferedInputStream;

	public static void main(String[] args) throws Exception {
		bufferedInputStream = new BufferedInputStream(new FileInputStream("demo\\c.txt"));
		// 一次读取一个字节
		// int by=0;
		// while ((by=bufferedInputStream.read())!=-1) {
		// System.out.print((char)by);
		//
		// }
		long oldTime = System.currentTimeMillis();
		byte[] bs = new byte[1024];
		int len = 0;
		// 一次读取一个字节数组
		while ((len = bufferedInputStream.read(bs)) != -1) {
			System.out.println(new String(bs, 0, len));
			// String(byte[] bytes, int offset, int length)
		}
		bufferedInputStream.close();
		long newTime = System.currentTimeMillis();
		long time = newTime - oldTime;
		System.out.println(time);
	}
}
字节缓冲输出流:
  构造方式:
  (第一种开发中) public BufferedOutputStream(OutputStream out):采用的默认的缓冲区大小(足够大了) ,来构造一个字节缓冲输出流对象
   public BufferedOutputStream(OutputStream out,int size):指定size缓冲区大小构造缓冲输出流对象
   IllegalArgumentException - 如果 size <= 0
  写数据的方式:
  一次写一个字节
  write(int by)
   一次写一个字节数组
   write(byte[] b, int off, int len) 
  方法:
   void flush() ;刷新缓冲区中的流
  面试题:
   字节缓冲输出流它的构造方法为什么不能直接传递路径/文件?
  缓冲输入流/缓冲输出流,它只是在底层提供一个缓冲区数组,
  底层实现文件的复制/读取/写入这些操作都依赖于基本流对象来操作(InputStream/OutputStream/FileInputStream/FileOutputstream)

 代码示例

 

public class BufferedOutputStreamDemo {

	public static void main(String[] args) throws Exception {
		// 构造一个字节缓冲输出流对象
		// public BufferedOutputStream(OutputStream out)
		/*
		 * OutputStream out = new FileOutputStream("out.txt") ; BufferedOutputStream bos
		 * = new BufferedOutputStream(out) ;
		 */

		// 符合Java的一种设计模式:装饰者设计模式(过滤器:Filter)
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));

		// 写数据
		bos.write("hello".getBytes());

		// 释放资源
		bos.close();

	}
}
存储文件
   IO流:永久存储(耗时)
   数据库:永久存储 
  基本的字节流
   文件字节输入流/文件字节输出流
        高效的字节流(缓冲流)
  操作一个视频文件,来测试速度问题
  基本的字节流一次读取一个字节 ://耗时:85772毫秒
  基本的字节流一次读取一个字节数组 :共耗时:216毫秒
  高效的字节流一次读取一个字节      :共耗时:682毫秒
  高效的字节流一次读取一个字节数组:共耗时:49毫秒

 代码示例

package io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Demo5 {
	public static void main(String[] args) throws Exception {
		long start = System.currentTimeMillis();
		// method1("f:\\a.jpg","copy1.jpg");//共耗时:891毫秒
		// method2("f:\\a.jpg","copy2.jpg");//共耗时:15毫秒
		// method3("f:\\a.jpg","copy3.jpg");//共耗时:31毫秒
		method4("f:\\a.jpg", "copy4.jpg");// 共耗时:0毫秒
		long end = System.currentTimeMillis();
		System.out.println("共耗时:" + (end - start) + "毫秒");
	}

	// 基本字节流一次读取一个字节
	private static void method1(String src, String dest) throws Exception {
		FileInputStream fileInputStream = new FileInputStream(src);
		FileOutputStream fileOutputStream = new FileOutputStream(dest);
		int by = 0;
		while ((by = fileInputStream.read()) != -1) {
			fileOutputStream.write(by);
		}
		fileInputStream.close();
		fileOutputStream.close();
	}

	// 基本字节流一次读取一个字节数组
	private static void method2(String src, String dest) throws Exception {
		FileInputStream fileInputStream = new FileInputStream(src);
		FileOutputStream fileOutputStream = new FileOutputStream(dest);
		byte[] bs = new byte[1024];
		int len = 0;
		while ((len = fileInputStream.read(bs)) != -1) {
			fileOutputStream.write(bs, 0, len);
		}
		fileInputStream.close();
		fileOutputStream.close();
	}

	// 高效字节流一次读取一个字节
	private static void method3(String src, String dest) throws Exception {
		BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(src));
		BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(dest));
		int by = 0;
		while ((by = bufferedInputStream.read()) != -1) {
			bufferedOutputStream.write(by);
		}
		bufferedInputStream.close();
		bufferedOutputStream.close();
	}

	// 高效字节流一次读取一个字节数组
	private static void method4(String src, String dest) throws Exception {
		BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(src));
		BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(dest));
		byte[] bs = new byte[1024];
		int len = 0;
		while ((len = bufferedInputStream.read(bs)) != -1) {
			bufferedOutputStream.write(bs, 0, len);
		}
		bufferedInputStream.close();
		bufferedOutputStream.close();
	}
}

使用字节流一次读取一个字节的方式,会造成中文乱码--->Java提供了一个字符流(专门用来解决中文乱码问题)

代码示例

public class FileInputStreamDemo {

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

		// 封装文件
		// 一次读取一个字节的方式
		FileInputStream fis = new FileInputStream("a.txt");

		// 读数据
		int by = 0;
		while ((by = fis.read()) != -1) {
			System.out.print((char) by);
		}

		// 释放资源
		fis.close();

	}
}

  编码和解码:前后的编码格式要一致!
  编码:
   简单理解:将能看懂的东西--->看不懂的东西
  解码:
  看不懂的东西---能看懂的东西
 
  举例: 谍战片
 
  今天老地方见...
  编码:
   今---->字节---->二进制数据
 
  解码:二进制数据-->十进制数据--->字节---->字符串
 
  
  编码: 将字符串变成一个字节数组
   public byte[] getBytes() :平台默认编码集(默认的是Gbk)
      public byte[] getBytes(Charset charset) ;"指定编码格式
  
  解码:将字节数组--->字符串
   public String(byte[] bytes) :使用平台默认编码集(gbk)
   public String(byte[] bytes,Charset charset):用指定的编码格式来解码

代码示例

public class StringDemo {

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

		// 定义一个字符串
		String str = "你好";

		// 编码和解码:前后必须一致

		// 编码
		// byte[] bys = str.getBytes() ;
		byte[] bys = str.getBytes("utf-8");// -28, -67, -96, -27, -91, -67]
		System.out.println(Arrays.toString(bys));// [-60, -29, -70, -61]
		System.out.println("------------------");

		// 解码
		// public String(byte[] bytes) :使用平台默认编码集(gbk)
		// String s = new String(bys) ;
		// String s = new String(bys, "GUK") ;//一个中文对应三个字节
		String s = new String(bys, "utf-8");// 一个中文对应三个字节
		System.out.println(s);

	}
}
 需求:将a.txt文件中的内容进行复制,复制到当前项目下(b.txt)

   文本文件:优先采用字符流
  
  源文件:a.txt---->Reader---->InputStreamReader---->FileReader

  目的的文件:b.txt--->Writer-->OutputStreamWriter---->FileWriter

代码示例

package io;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Demo8 {
	public static void main(String[] args) throws Exception {
		InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("src\\io\\demo7.java"));
		OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("aa.txt"));
		// 一次读取一个字符数组
		/*
		 * char [] cs=new char[1024]; int len=0; while
		 * ((len=inputStreamReader.read(cs))!=-1){ outputStreamWriter.write(cs, 0, len);
		 * } inputStreamReader.close(); outputStreamWriter.close();
		 */
		// 一次读取一个字符
		/*
		 * int ch=0; while ((ch=inputStreamReader.read())!=-1) {
		 * outputStreamWriter.write((char)ch); } inputStreamReader.close();
		 * outputStreamWriter.close();
		 */
		// 方式2:使用便捷类进行操作
		FileReader fileReader = new FileReader("src//io//Demo8.java");
		FileWriter fileWriter = new FileWriter("bb.java");
		// 一次读取一个字符数组
		char[] cs = new char[1024];
		int len = 0;
		while ((len = fileReader.read(cs)) != -1) {
			fileWriter.write(cs, 0, len);
		}
		fileReader.close();
		fileWriter.close();
	}
}
字符转换输入流:InputStreamReader
 InputStreamReader(InputStream in) :构造一个字符转换输入流,默认编码
 public InputStreamReader(InputStream in,Charset cs) 构造一个字符转换输入流,指定编码

 字符转换输入流=字节流+编码格式

代码示例

public class ReaderDemo {

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

		// 需求:要读取当前项目下的osw.txt,将内容输出在控制台上
		// InputStreamReader isr =
		// new InputStreamReader(
		// new FileInputStream("osw.txt", "utf-8") ;

		InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"), "gbk");

		// 读数据
		// 一次读取一个字符数组
		char[] chs = new char[1024];
		int len = 0;
		while ((len = isr.read(chs)) != -1) {
			System.out.println(new String(chs, 0, len));
		}

		// 关闭资源
		isr.close();
	}
}
字符输出流写数据的功能:
  public void write(int c):写单个字符 
  public void write(char[] cbuf):写字符数组
  public abstract void write(char[] cbuf, int off,  int len):写字符数组的一部分
  public void write(String str):写字符串
  public void write(String str,int off, int len):写字符串的某一部分
flush和close方法的区别?
  close:关闭该流,关闭该流对象以及与它相关联的资源文件,关闭之后,不能再对流对象进行操作了,否则会有异常
  flush:刷新该流,防止一些文件(图片文件/音频文件)缺失,或者没有加载到流对象中,刷新了该流,还是可以对流对象进行操作
 字符缓冲输入流/字符缓冲输出流
 杂七杂八的流(properties:属性集合类/合并流/序列化Serializable/内存操作流)

 NIO

代码示例

package io;

import java.io.FileWriter;

public class Demo10 {
	public static void main(String[] args) throws Exception {
		// 创建字符输出流对象
		FileWriter fileWriter = new FileWriter("cc.txt");
		// 写一个字符
		fileWriter.write('a');
		fileWriter.write(97);
		// 刷新流
		fileWriter.flush();
		fileWriter.write(98);
		fileWriter.flush();
		char[] cs = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k' };
		// 写一个字符数组
		fileWriter.write(cs);
		// 写一个字符数组
		fileWriter.write(cs, 0, 5);
		fileWriter.flush();
		// 写字符串
		fileWriter.write("我爱高圆圆!!!");
		fileWriter.flush();
		// 写字符串的一部分
		fileWriter.write("我爱高圆圆", 0, 4);
		fileWriter.flush();
		fileWriter.close();// 关闭流之前一定要刷新流
	}
}
先使用字符缓冲输出流写数据,再使用字符缓冲输入流读数据,显示控制台上
字符缓冲输出流:
特有功能:public void newLine():写入行分隔符
字符缓冲输入流:

  特有功能:public String readLine():一次读取一行

代码示例

package io;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;

public class Demo11 {
	public static void main(String[] args) throws Exception {
		write();
		BufferedReader bufferedReader = new BufferedReader(new FileReader("hhh.java"));
		/*
		 * String string=bufferedReader.readLine(); System.out.println(string);
		 * string=bufferedReader.readLine(); System.out.println(string);
		 * string=bufferedReader.readLine(); System.out.println(string);
		 */
		// 代码在重复,改进版
		String line = null;
		while ((line = bufferedReader.readLine()) != null) {
			System.out.println(line);
		}
	}

	private static void write() throws Exception {
		BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("hhh.java"));
		// 写数据
		for (int x = 0; x < 10; x++) {
			bufferedWriter.write("hello" + x);
			bufferedWriter.newLine();
			bufferedWriter.flush();
		}
		bufferedWriter.close();
	}
}
BufferedReader:字符缓冲输入流
  构造方法
  public BufferedReader(Reader in)默认缓冲区大小构造字符缓冲输入流对象。 
   public BufferedReader(Reader in, int size)制定缓冲区大小构造字符缓冲输入流。

  需求:读取当前项目下的bw.txt这个文件

package io;

import java.io.BufferedReader;
import java.io.FileReader;

public class Demo12 {
	public static void main(String[] args) throws Exception {
		// 创建字符缓冲输入流对象
		BufferedReader bufferedReader = new BufferedReader(new FileReader("src\\io\\Demo11.java"));
		char[] ch = new char[1024];
		int len = 0;
		while ((len = bufferedReader.read(ch)) != -1) {
			System.out.println(new String(ch, 0, len));
		}
		bufferedReader.close();
	}
}
在字符流中提供了一个更高效的流-->字符缓冲流

  字符缓冲输入流

  字符缓冲输出流

   BufferedWrier:文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入
   构造方法
  BufferedWriter(Writer out) :默认缓冲区大小构造字符缓冲输出流对象
  BufferedWriter(Writer out,int size):指定缓冲区大小构造字符缓冲输出流对象

代码示例

package io;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class Demo13 {
	public static void main(String[] args) throws IOException {
		BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("bw.txt"));
		bufferedWriter.write("hello");
		bufferedWriter.newLine();
		bufferedWriter.write("world");
		// 刷新流
		bufferedWriter.flush();
		// 关闭资源
		bufferedWriter.close();
	}
}
使用字符缓冲流进行复制操作
 分别使用两种方式
  1)一次读取一个字符数组

  2)一次读取一行 

代码示例

package io;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;

public class Demo14 {
	public static void main(String[] args) throws Exception {
		BufferedReader bufferedReader = new BufferedReader(new FileReader("src\\io\\Demo12.java"));
		BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("copy.java"));
		// 一次读取一个字符数组
		/*
		 * char[] cs=new char[1024]; int len =0; while
		 * ((len=bufferedReader.read(cs))!=-1) { bufferedWriter.write(cs, 0, len);
		 * bufferedWriter.flush(); } bufferedReader.close(); bufferedWriter.close();
		 */
		// 一次读取一行
		String line = null;
		while ((line = bufferedReader.readLine()) != null) {
			bufferedWriter.write(line);
			bufferedWriter.newLine();
			bufferedWriter.flush();
		}
		bufferedReader.close();
		bufferedWriter.close();
	}
}
需求:把ArrayList集合中的字符串数据存储到文本文件

ArrayList集合存储的元素为String类型,可以存储一些字符串
   使用增强for遍历ArrayList
  使用BufferedWriter(文本文件)
 
 
  源文件:ArrayList<String>

  目的地:BufferedWriter输出文本文件,给文件中写入字符

代码示例

package io;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.ArrayList;

public class Demo15 {
	public static void main(String[] args) throws Exception {
		ArrayList<String> arrayList = new ArrayList<String>();
		arrayList.add("hello");
		arrayList.add("world");
		arrayList.add("javaweb");
		// 创建一个字符缓冲输出流
		BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("arrayList.java"));
		// 使用增强for进行遍历
		for (String string : arrayList) {
			bufferedWriter.write(string);
			bufferedWriter.newLine();
			bufferedWriter.flush();
		}
		bufferedWriter.close();
	}
}
复制文本文件(5种方式分别完成)
  文本文件:字符流 
  基本字符流一次读取一个字符
  一次读取一个字符数组
  字符缓冲流一次读取一个字符
  一次读取一个字符数组

  一次读取一行

代码示例

package io;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;

public class Demo16 {
	public static void main(String[] args) throws Exception {
		// method1("src//io/Demo15.java","copy.java");
		method2("src//io/Demo15.java", "copy1.java");
	}

	private static void method1(String src, String dest) throws Exception {
		BufferedReader bufferedReader = new BufferedReader(new FileReader(src));
		BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(dest));
		// 一次读取一个字符数组
		char[] cs = new char[1024];
		int len = 0;
		while ((len = bufferedReader.read(cs)) != -1) {
			bufferedWriter.write(cs, 0, len);
			bufferedWriter.newLine();
			bufferedWriter.flush();
		}
		bufferedReader.close();
		bufferedWriter.close();
	}

	private static void method2(String src, String dest) throws Exception {
		BufferedReader bufferedReader = new BufferedReader(new FileReader(src));
		BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(dest));
		// 一次读取一行
		String line = null;
		while ((line = bufferedReader.readLine()) != null) {
			// 一次写入一行
			bufferedWriter.write(line);
			bufferedWriter.newLine();
			bufferedWriter.flush();
		}
		bufferedReader.close();
		bufferedWriter.close();
	}
}
需求:有一个文本文本,需要将文本文件中的内容放到ArrayList集合中,遍历集合获取元素 
 源文件:b.txt----->读取---->BuffferedReader

 目的地:ArrayList<String>

代码示例

package io;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.ArrayList;

public class Demo17 {
	public static void main(String[] args) throws Exception {
		BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("hhh.java"));
		BufferedReader bufferedReader = new BufferedReader(new FileReader("hhh.java"));
		ArrayList<String> arrayList = new ArrayList<String>();
		// 创建文件
		for (int i = 0; i < 100; i++) {
			bufferedWriter.write("hello java world!!!  " + i);
			bufferedWriter.newLine();
			bufferedWriter.flush();
		}
		// 读取文件
		String line = null;
		while ((line = bufferedReader.readLine()) != null) {
			// 将文件中的内容读取出来存储在arrayList数组中
			arrayList.add(line);
		}
		for (String string : arrayList) {
			System.out.println(string);
		}
		bufferedReader.close();
		bufferedWriter.close();
	}
}
需求:我有一个文本文件中存储了几个名称,请大家写一个程序实现随机获取一个人的名字。 
  1)封装一个文本文件:使用字符缓冲输入流读文件
  2)创建一个ArrayList<String>
  3)使用字符缓冲输入流readLine(),一次读取一行,就将该行数据添加到集合中
  4)创建Random类对象
  5)Random类对象.nextInt(集合对象.size()) ;

  6)通过角标get(int index ):获取内容

代码示例

package io;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;

public class Demo18 {
	private static Scanner in;

	public static void main(String[] args) throws Exception {
		BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("hhh.txt"));
		BufferedReader bufferedReader = new BufferedReader(new FileReader("hhh.txt"));
		ArrayList<String> arrayList = new ArrayList<String>();
		// 创建文件
		System.out.println("请输入人名");
		in = new Scanner(System.in);
		for (int i = 0; i < 3; i++) {
			String name = in.nextLine();
			bufferedWriter.write(name);
			bufferedWriter.newLine();
			bufferedWriter.flush();
		}
		// 一次读取一行
		String line = null;
		while ((line = bufferedReader.readLine()) != null) {
			arrayList.add(line);
		}
		bufferedReader.close();
		bufferedWriter.close();
		// 创建Random类对象
		Random random = new Random();
		// 获取随机数
		int index = random.nextInt(arrayList.size());
		// 通过角标查找对应元素
		String name = arrayList.get(index);
		System.out.println("幸运的人是:" + name);
	}
}
内存操作流:适用于临时存储文件.
内存操作输入流:byteArrayInputStream
  ByteArrayInputStream(byte[] buf) 
  内存操作输出流: byteArrayOutputStream
  构造方法:ByteArrayOutputStream() 
 内存操作流:一个程序结束后,那么流对象就会从内存中消失

代码示例

package io;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

public class Demo19 {
	public static void main(String[] args) throws Exception {
		// 创建内存操作输出流对象
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		for (int i = 0; i < 10; i++)
			byteArrayOutputStream.write(("helloworld" + i + "  ").getBytes());
		// 此流不需要关闭
		byte[] buf = byteArrayOutputStream.toByteArray();
		// 创建内存操作输入流对象
		ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(buf);
		// 一次读取一个字节
		int by = 0;
		while ((by = byteArrayInputStream.read()) != -1) {
			System.out.print((char) by);
		}
	}
}

打印流 PrintWriter

源文件:StringDemo.java --->BufferedReader

 目的文件:Copy.java   ----->PrintWriter

代码示例

public class CopyFileDemo {

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

		// 封装文件
		BufferedReader br = new BufferedReader(new FileReader("StringDemo.java"));
		PrintWriter pw = new PrintWriter(new FileWriter("Copy.java", true));

		// 一次读取一行
		String line = null;
		while ((line = br.readLine()) != null) {
			// 向打印输出内容
			pw.println(line);

		}

		// 释放资源
		pw.close();
		br.close();
	}
}

 数据流:针对基本类型的数据进行读写操作
 数据输入流:DataInputStream
 数据输出流:DataOutputStream 

代码示例

package org.westos.io;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Demo {
	public static void main(String[] args) throws Exception {
		write();
		read();
	}

	private static void write() throws Exception {
		DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("dos.txt"));
		dataOutputStream.writeInt(10);
		dataOutputStream.writeShort(100);
		dataOutputStream.writeByte(120);
		dataOutputStream.writeDouble(12.34);
		dataOutputStream.writeFloat(12.56F);
		dataOutputStream.writeBoolean(true);
		dataOutputStream.writeChar('a');
		dataOutputStream.close();
	}

	private static void read() throws Exception {
		DataInputStream dataInputStream = new DataInputStream(new FileInputStream("dos.txt"));
		int i = dataInputStream.readInt();
		short s = dataInputStream.readShort();
		byte b = dataInputStream.readByte();
		double d = dataInputStream.readDouble();
		float f = dataInputStream.readFloat();
		boolean flag = dataInputStream.readBoolean();
		char c = dataInputStream.readChar();
		dataInputStream.close();
		System.out.println(i);
		System.out.println(s);
		System.out.println(b);
		System.out.println(d);
		System.out.println(f);
		System.out.println(flag);
		System.out.println(c);
	}
}

 打印流
  字符打印流(针对文本进行操作:PrintWriter)
  字节打印流(printStream 和标准输出流有关系 System.out;)  
 PrintWriter:属于输出流
1)只能写数据(只能针对目的地文件进行操作),不能读数据(不能针对源文件进行操作)
2)可以针对文本文件直接进行操作
  如果一个类的构造方法里面有File对象或者String类型数据,这个类可以对文本文件直接操作
  FileInputStream
  FileOutputStream
  FileWriter
FileReader..
  PrintWriter
  3)自动刷新功能::PrintWriter(OutputStream out/Writer out,boolean autoflush);第二个参数如果是true 表示启动自动刷新功能
  4)打印的方法:print(XXX x)/println(XXX  xx)

package org.westos.io;

import java.io.FileWriter;
import java.io.PrintWriter;

public class Demo2 {
	public static void main(String[] args) throws Exception {
		PrintWriter printWriter = new PrintWriter(new FileWriter("pw.java"));
		printWriter.println("hello");// 自动换行并且向pw.java文件打印内容
		printWriter.println("java");
		printWriter.println("world");
		printWriter.flush();
		printWriter.close();
	}
}

输出一个文本文件,启动PrintWriter的自动刷新功能

package org.westos.io;

import java.io.FileWriter;
import java.io.PrintWriter;

public class Demo3 {
	public static void main(String[] args) throws Exception {
		PrintWriter printWriter = new PrintWriter(new FileWriter("pw2.java"), true);
		printWriter.println("hello");
		printWriter.println("world");
		printWriter.println("javaEE");
		printWriter.close();
	}
}
SequenceInputStream 表示其他输入流的逻辑串联(合并流)
 构造方法
 public SequenceInputStream(InputStream s1, InputStream s2)
 复制文件
   a.txt----->b.txt
   c.txt----->d.txt
  
  现在的需求:
   a.txt+b.txt--->c.txt

  StringDemo.java+SystemInDemo.java---->Copy.java

代码示例

package io;

import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.SequenceInputStream;

public class Demo3 {
	public static void main(String[] args) throws Exception {
		InputStream in1 = new FileInputStream("src\\io\\Demo.java");
		InputStream in2 = new FileInputStream("src\\io\\Demo3.java");

		// 创建合并流对象
		SequenceInputStream sis = new SequenceInputStream(in1, in2);
		// 创建一个字节缓冲输入流对象
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Copy.java"));

		// 原来怎么读写,现在依然这样读写
		byte[] bys = new byte[1024];
		int len = 0;
		while ((len = sis.read(bys)) != -1) {
			bos.write(bys, 0, len);
			bos.flush();
		}

		// 关闭资源
		sis.close();
		bos.close();

	}
}

sequenceInputStream另一种构造方式
 public SequenceInputStream(Enumeration e) 
  将多个输入流对象进行合并

  a.txt+b.txt+c.txt--->d.txt

代码示例

public class SequenceInputStreamDemo2 {

	public static void main(String[] args) throws IOException {
		// StringDemo.java+SystemInDemo.java+PrintWriterDemo.java--->Copy.java文件中

		// 定义一个集合Vector
		Vector<InputStream> v = new Vector<InputStream>();
		// 使用InputStream封装文件
		InputStream s1 = new FileInputStream("StringDemo.java");
		InputStream s2 = new FileInputStream("SystemInDemo.java");
		InputStream s3 = new FileInputStream("PrintWriterDemo.java");

		// 将流对象添加到集合中
		v.add(s1);
		v.add(s2);
		v.add(s3);

		// 特有功能
		Enumeration<InputStream> en = v.elements();

		// 创建合并输入流对象
		SequenceInputStream sis = new SequenceInputStream(en);
		// 创建字节缓冲输出流对象
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Copy.java"));

		// 一次读取一个字节数组
		byte[] bys = new byte[1024];
		int len = 0;
		while ((len = sis.read(bys)) != -1) {
			bos.write(bys, 0, len);
			bos.flush();
		}

		// 关闭资源
		bos.close();
		sis.close();
	}
}
sequenceInputStream另一种构造方式
 public SequenceInputStream(Enumeration e) 
  将多个输入流对象进行合并

  a.txt+b.txt+c.txt--->d.txt

代码示例

public class SequenceInputStreamDemo2 {

	public static void main(String[] args) throws IOException {
		// StringDemo.java+SystemInDemo.java+PrintWriterDemo.java--->Copy.java文件中

		// 定义一个集合Vector
		Vector<InputStream> v = new Vector<InputStream>();
		// 使用InputStream封装文件
		InputStream s1 = new FileInputStream("StringDemo.java");
		InputStream s2 = new FileInputStream("SystemInDemo.java");
		InputStream s3 = new FileInputStream("PrintWriterDemo.java");

		// 将流对象添加到集合中
		v.add(s1);
		v.add(s2);
		v.add(s3);

		// 特有功能
		Enumeration<InputStream> en = v.elements();

		// 创建合并输入流对象
		SequenceInputStream sis = new SequenceInputStream(en);
		// 创建字节缓冲输出流对象
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Copy.java"));

		// 一次读取一个字节数组
		byte[] bys = new byte[1024];
		int len = 0;
		while ((len = sis.read(bys)) != -1) {
			bos.write(bys, 0, len);
			bos.flush();
		}

		// 关闭资源
		bos.close();
		sis.close();
	}
}
标准的输入输出流
  InputStream in = System.in 
  PrintStream out = System.out ;
 jdk5以后,Java--->Scanner(InputStream in)
  键盘录入
1)Scanner

  2)BufferedReader里面包装字符转换输入流,包装System.in

代码示例

package io;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Demo5 {
	public static void main(String[] args) throws Exception {
		InputStream inputStream = System.in;
		InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
		BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
		// BufferedReader bufferedReader=new BufferedReader(new
		// InputStreamReader(System.in));
		System.out.println("请输入一个字符串:");
		String line = bufferedReader.readLine();
		System.out.println("你输入的字符串为:" + line);
		System.out.println("请输入一个整数:");
		String integer = bufferedReader.readLine();
		// 强制类型转换
		int num = Integer.parseInt(integer);
		System.out.println("你输入的整数为:" + num);
	}
}
标准输出流
 * PrintStream ps = System.out ; 
 *使用BufferedWriter 去包装System.out
package io;

import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.io.PrintStream;

public class Demo6 {
	public static void main(String[] args) throws Exception {
		/*
		 * System.out.println("我爱高圆圆");
		 * System.out.println("--------------------------------");
		 */
		PrintStream printStream = System.out;
		printStream.println("我爱高圆圆");
		System.out.println("---------------------------------");
		BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));
		bufferedWriter.write("hello");
		bufferedWriter.newLine();
		bufferedWriter.write("java");
		;
		bufferedWriter.newLine();
		bufferedWriter.write("world");
		bufferedWriter.newLine();
		bufferedWriter.flush();
		bufferedWriter.close();
	}
}

序列化流  ObjectInputStream

                ObjectOutputStream

java.io.NotSerializableException :当前类未实现序列化功能的异常
  
   Serializable:接口 没有构造方法,没有字段,也没有方法
   接口---->标记接口
   
   自定义类要实现序列化功能,必须实现Serializable接口
   
   类实现了serializable也意味着他是标记类
   
    假设之前针对Peroson操作序列的时候,产生一个标记  Preson.class--->固定ID 100
 
   name -100
    age -100
   
    已经序列化完毕了,然后又修改了Person类里面的一些东西,加入了toString()
   Person.class---固定id -- 200
   
   
   org.westos_01.Person; local class incompatible: 
    stream classdesc serialVersionUID = -428218385429329797, 
    local class serialVersionUID = -5865763454468005049
   
   
   因为手动修改了这些类的属性/成员变量,将序列化版本Id改变了
   InvalidClassException:一般情况:该类的序列版本号与从流中读取的类描述符的版本号不匹配 
   实际开发中,不想多次对当前这些序列化,如果这样做,非常麻烦?
   如何解决呢?
  让当前实现序列化功能的这个类产生一个固定ID,注意看程序有黄色警告线,直接就点它固定Id
   比如:当前的这个类中有很多属性(性别,地址,学号...),某些属性不想被序列化,如何解决这样一个问题

代码示例

package io2;

import java.io.Serializable;

public class Person implements Serializable {
	private String name;
	transient int age;
	// private int age;

	public Person() {
		super();
		// TODO Auto-generated constructor stub
	}

	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;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}

}
package io2;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Demo {
	private static ObjectOutputStream objectOutputStream;
	private static ObjectInputStream objectInputStream;

	public static void main(String[] args) throws Exception, Exception {
		write();
		read();
	}

	// 反序列化流对象 ObjectInputStream
	private static void read() throws Exception, IOException {
		objectInputStream = new ObjectInputStream(new FileInputStream("oos.txt"));
		Object object = objectInputStream.readObject();
		objectInputStream.close();
		System.out.println(object);
	}

	// 序列化流对象 ObjectOutputStream
	private static void write() throws Exception, IOException {
		objectOutputStream = new ObjectOutputStream(new FileOutputStream("oos.txt"));
		// Person person=new Person("高圆圆",37);
		Person person2 = new Person("赵又廷", 39);
		// objectOutputStream.writeObject(person);
		objectOutputStream.writeObject(person2);

	}
}
Properties:表示了一个持久的属性集(简称:属性集合类)  extends Hashtable<K,V> Map集合的
  可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。

  public Properties():无参构造

代码示例

public class PropertiesDemo {

	public static void main(String[] args) {

		// 它继承Hashtable
		// 创建一个属性集合类对象
		// Properties<String,String> prop = new Properties<String,String>() ;
		Properties prop = new Properties();
		System.out.println(prop);
		System.out.println("---------------------");

		// 给属性集合类中的属性列表添加元素
		prop.put("高圆圆", "赵又廷");
		prop.put("文章", "马伊琍");
		prop.put("黄晓明", "baby");

		System.out.println(prop);

		// 遍历属性集合类
		Set<Object> keySet = prop.keySet();
		for (Object key : keySet) {
			Object value = prop.get(key);
			System.out.println(key + "=" + value);
		}
	}
}
属性集合类的特有功能:
  public Object setProperty(String key, String value) :给属性列表中添加键和值,并且强制都使用String
  public Set<String> stringPropertyNames():遍历的功能

  public String getProperty(String key)用指定的键在此属性列表中搜索属性

代码示例

public class PropertiesDemo2 {

	public static void main(String[] args) {

		// 创建属性集合类对象
		Properties prop = new Properties();

		// 添加元素
		prop.setProperty("张三", "20");
		prop.setProperty("李四", "22");
		prop.setProperty("王五", "18");

		// 遍历
		// 获取所有的键的集合
		Set<String> keyset = prop.stringPropertyNames();
		for (String key : keyset) {
			// 通过键找值
			String value = prop.getProperty(key);
			System.out.println(key + "----" + value);
		}
	}
}
可以保存在流中或从流中加载,只能使用属性集合类
 public void store(Writer writer,String comments):把集合中的数据保存到文本文件中(属性集合)
 public void load(Reader reader):将文本文件中的数据加载到属性集合中
 
 举例:

  打游戏:游戏进度的保存和游戏加载

代码示例

package io2;

import java.io.FileReader;
import java.io.FileWriter;
import java.util.Properties;

public class Demo4 {
	public static void main(String[] args) throws Exception {
		myStore();
		myLoad();
	}

	private static void myLoad() throws Exception {
		Properties properties = new Properties();
		FileReader fileReader = new FileReader("name.txt");
		// 将文本文件中的数据加载到属性集合中
		properties.load(fileReader);
		fileReader.close();
		System.out.println(properties);
	}

	private static void myStore() throws Exception {
		// 创建一个属性集合类对象
		Properties properties = new Properties();
		properties.setProperty("张三", "20");
		properties.setProperty("文章", "29");
		properties.setProperty("成龙", "55");
		FileWriter fileWriter = new FileWriter("name.txt");
		// 将属性集合中的数据存储到文本文件中
		properties.store(fileWriter, "name's content");
		fileWriter.close();
	}
}

通过属性集合查找文本文件中的数据,如果存在则进行修改

代码示例

package io2;

import java.io.FileReader;
import java.io.FileWriter;
import java.util.Properties;
import java.util.Set;

public class Demo5 {
	public static void main(String[] args) throws Exception {
		Properties properties = new Properties();
		FileReader fileReader = new FileReader("demo\\name.txt");
		properties.load(fileReader);
		System.out.println(properties);
		fileReader.close();
		// 遍历属性集合
		Set<String> keySet = properties.stringPropertyNames();
		for (String key : keySet) {
			if ("文章".equals(key)) {
				properties.setProperty(key, "666");
			}
		}
		System.out.println(properties);
		FileWriter fileWriter = new FileWriter("demo\\name.txt");
		properties.store(fileWriter, "name's content");
	}
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值