-------android培训、java培训、期待与您交流! ----------
01.IO流(概述)
1.IO(Input Output)流
1)IO流用来处理设备之间的数据传输
2)java对数据的操作是通过流的方式
3)java且用于操作流的对象都在IO包中
4)流按操作数据分为两种:字节流与字符流。
(1)字符流:方便处理文本数据。
(2)编码表:国际统一码表-----Unicode--->UTF-8(优化扩展)
美国-------------ASCII表
中国-------------GB2312--->GBK(扩展)
(3)不同码表之间排码就会产生乱码,字符流的出现在内部隔合了编码表,
因为可以为读到的字节数据指定编码表,在处理文字数据时就会很方便。
5)流按流向分为:输入流,输出流。
2.IO流常用基类
1)字节流的抽象基类:InputStream, OutputStream
2)字符流的抽象基类:Reader, Writer
注:由这四个类派生出来的子类名称都是以其父类名
作为子类名的后缀。
eg: InputStream的子类FileInputStream.
eg: Reader的子类FileReader
02.IO流(FileWriter)
1.字符流和字节流:
字节流两个基类:
InputStream OutputStream
字符流两个基类:
Reader Writer
2.(java.io包)Writer--子类-->OutputStreamWriter--子类-->FileWriter
1)Writer抽象类中方法:
(1)abstract void close()
关闭此流,但要先刷新它。
(2)abstract void flush()
刷新该流的缓冲。
(3)void write(String str)
写入字符串。
注:写入字符流的抽象类。子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()。
但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能
2)OutputStreamWriter类中方法:
(1)void close()
关闭此流,但要先刷新它。
(2)void flush()
刷新该流的缓冲
注:OutputStreamWriter 是字符流通向字节流的桥梁。
3)FileWriter类的构造方法:
(1)FileWriter(String fileName)
根据给定的文件名构造一个 FileWriter 对象。
注:Writer类用来写入字符文件的便捷类。
此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。
3.先学习一下字符流的特点。
既然IO流是用于操作数据的,
那么数据的最常见体现形式是:文件。
那么先以操作文件为主来演示。
需求:在硬盘上,创建一个文件并写入一些文字数据。
找到一个专门用于操作文件的Writer子类对象FileWriter.后缀名是父类名。前缀名是该流对象的功能。
4.代码演示:
import java.io.*;
class FileWriterDemo
{
public static void main(String[] args) throws IOException
{
//创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件。
//而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
//其实该步就是在明确数据要存放的目的地。
FileWriter fw = new FileWriter("demo.txt");
//调用write方法,将字符串写入到流中。
fw.write("abcde");
//刷新流对象中的缓冲中的数据。
//将数据刷到目的地中。
//fw.flush();
//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。
//将数据刷到目的地中。
//和flush区别:flush刷新后,流可以继续 使用,close刷新后,会将流关闭。
fw.close();
fw.write("haha");
}
}
03.IO流(IO异常处理方式)
1.凡是能和设备上的数据发生关联的,调用底层资源的都会发生IOException。
2."K:\\demo.txt"没有K盘,会抛出出FileNotFoundException(系统找不到指定的路径)异常。
FileNotFoundException是IOException的子类。
3.初始化抛出异常,说明初始化失败,fw还为空,故不可调用对象的close()方法,
所以抛出NullPointerException异常,finally中一定要对关闭的流对象进行不等于空的判断。
04.IO流(文件的续写)
1.FileWriter的加一个重载构造函数:
public FileWriter(String fileName,boolean append) throws IOException
根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。
参数:
fileName - 一个字符串,表示与系统有关的文件名。
append - 一个 boolean 值,如果为 true,则将数据写入文件末尾处,而不是写入文件开始处。
2.换行符:
1)Linux下的换行: \n
2)Windows下的换行:\r\n
3)java即支持\n又支持\r\n,有时用windows的记事本直接打开源文件会是一堆无序的乱码,
而放到EditPlus中就可以有序显示出来,这就是由于windows不支持\n的原因。
05.IO流(文本文件读取方式一)
Reader--->FileReader(java.io包中)
1.Reader类
用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。
但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。
1)构造方法:
protected Reader() //protected说明只有子类可使用。
创建一个新的字符流 reader,其重要部分将同步其自身的 reader。
2)特有方法:
(1)abstract void close()
关闭该流并释放与之关联的所有资源。
(2)int read()
public int read()throws IOException
读取单个字符。在字符可用、发生 I/O 错误或者已到达流的末尾前,
此方法一直阻塞。用于支持高效的单字符输入的子类应重写此方法。
返回:
作为整数读取的字符,范围在 0 到 65535 之间 (0x00-0xffff),
如果已到达流的末尾,则返回 -1
(3)int read(char[] cbuf)
将字符读入数组。
2.FileReader类
1)public class FileReader extends InputStreamReader
用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。
要自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader。
FileReader 用于读取字符流。要读取原始字节流,请考虑使用 FileInputStream。
2)构造函数:
public FileReader(File file) throws FileNotFoundException
在给定从中读取数据的 File 的情况下创建一个新 FileReader。
3.代码演示:
//创建一个文件读取流对象,和指定名称的文件相关联。
//要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException
FileReader fr = new FileReader("demo.txt");
//调用读取流对象的read方法。
//read():一次读一个字符。而且会自动往下读。
int ch = 0;
while ((ch=fr.read()) != -1)
{
System.out.println((char)ch);
}
06.IO流(文本文件读取方式二)
第二种方式:通过字符数组进行读取。
1.read(char[] chs)方法
public int read(char[] cbuf)
throws IOException将字符读入数组。在某个输入可用、发生 I/O 错误或者已到达流的末尾前,此方法一直阻塞。
参数:
cbuf - 目标缓冲区
返回:
读取的字符数,如果已到达流的末尾,则返回 -1
抛出:
IOException - 如果发生 I/O 错误
2.原理图分析:如Day18-11-文本文件读取方式二。
3.代码演示:
FileReader fr = new FileReader("demo.txt");
//定义一个字符数组。用于存储读到字符。
//该read(char[])返回的是读到字符个数。
char[] buf = new char[1024];
int num = 0;
while ((num=fr.read(buf)) != -1)
{
System.out.println(new String(buf,0,num));
}
fr.close();
07.IO流(文本文件读取练习)
1.读取一个.java文件,并打印在控制台上。
2.拷贝文本文件:将C盘一个文本文件复制到D盘。
复制的原理:
其实就是将C盘下的文件数据存储到D盘的一个文件中。
步骤:
1,在D盘创建一个文件,用于存储C盘文件中的数据。
2,定义读取流和C盘文件关联。
3,通过不断的读写完成数据存储。
以下是我的程序代码。
/*
//Writer里面都是字符数组,而OutputStream里面都是字节数组。
import java.io.*;
class FileOutputStreamDemo{
public static void main(String args[])throws IOException{
writeFile();
readFile_4();
}
public static void readFile_1()throws IOException{
FileInputStream fis = new FileInputStream("fos.txt");
int temp;
while((temp=fis.read())!=-1){
System.out.println((char)temp);//此处只能强转为char
}
fis.close();
}
public static void readFile_2()throws IOException{
FileInputStream fis = new FileInputStream("fos.txt");
int temp,i=0;
byte[] b = new byte[10];
while((temp=fis.read())!=-1){
b[i++]=(byte)temp;
}
fis.close();
System.out.println(new String(b,0,i));
}
public static void readFile_3()throws IOException{
FileInputStream fis = new FileInputStream("fos.txt");
int temp;
byte[] b = new byte[1024];//还是以这种方式为主。
while((temp=fis.read(b))!=-1){
System.out.println(new String(b,0,temp));
}
fis.close();
}
public static void readFile_4()throws IOException{//数据量太大的话,不建议使用这种方式。
FileInputStream fis = new FileInputStream("fos.txt");
byte[] buf = new byte[fis.available()];//定义一个刚刚好的缓冲区,不用循环了。
fis.read(buf);
System.out.println(new String(buf));
fis.close();
}
public static void writeFile() throws IOException{
FileOutputStream fos = new FileOutputStream("fos.txt");
fos.write("abcde".getBytes());
fos.close();//字节流中不涉及刷新动作。
}
}
//复制一个图片。1 ,用字节读取流对象和图片关联,2 ,用字节写入流对象创建一个图片文件
//不要拿字符流去复制媒体文件!!!!,可能复制了打不开,码表变了。
//字符流只用来处理文字数据。!!!!!!!!
import java.io.*;
class FileOutputStreamDemo{
public static void main(String args[]){
FileOutputStream fos = null;
FileInputStream fis = null;
try
{
fos = new FileOutputStream("d:\\22.jpg");
fis = new FileInputStream("d:\\11.jpg");
byte[] buf = new byte[1024];
int len ;
while((len=fis.read(buf))!=-1){
fos.write(buf,0,len);
}
}
catch (IOException e)
{
throw new RuntimeException("复制文件失败");
}finally{
try
{
if(fis!=null)
fis.close();
}
catch (IOException e)
{
throw new RuntimeException("读取关闭失败");
}
try
{
if(fos!=null)
fos.close();
}
catch (IOException e)
{
throw new RuntimeException("写入关闭失败");
}
}
}
}
//演示mp3的复制,通过缓冲区。
//BufferedOutputStream BufferedInputStream
import java.io.*;
class FileOutputStreamDemo{
public static void main(String args[])throws IOException{
long start = System.currentTimeMillis();
copy_1();
long end = System.currentTimeMillis();
System.out.println((end-start)+"毫秒");
}
public static void copy_1() throws IOException{
BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("d:\\11.mp3"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("d:\\22.mp3"));
int by = 0;
while((by=bufis.read())!=-1){
bufos.write(by);
}
bufos.close();
bufis.close();
}
}
//mp3中的数据都是二进制中的数据,由1010组成的。
//读一个字节相当于读了8个二进制位。
//自定义字节流缓冲区
//byte: -1 -->int: -1;
//11111111
//11111111-11111111-11111111-11111111 //还是-1,
//为什么不用byte而用int来接收呢?为避免读到8个1(-1)和我判断的结束标记相同,
//我可以把int的前3个字节补0,而不补1 ,
//00000000-00000000-00000000-11111111 //结束是255;这就是返回int类型的原因,进行提升前并补0,
//11111111 --> 提升了一个int类型,那不还是-1吗?是-1的原因
//是因为在8个1前面补的是1导致的。
//那么我只要在前面补0,即可保留原来字节数据不变,又可以避免
//-1的出现。怎么补0呢? &255 &oxff;
//11111111-11111111-11111111-11111111
//00000000-00000000-00000000-11111111
//-------------------------------------
//00000000-00000000-00000000-11111111
//read方法在做类型的提升,write方法在做类型的向下强转。
//当类型提升后,存储空间,由原来的1个字节变为了4 个字节,
//那么,目标数据应为原数据的4 倍呀,为什么和原来数据的大小
//一样,read方法在向上提升,而write方法在做一个强转动作,,
//它把最低的1 个字节保留,把前3个字节,砍了。
import java.io.*;
class MyBufferedInputStream{
private InputStream in;
private byte[] buf = new byte[1024];
private int pos = 0,count = 0;
MyBufferedInputStream(InputStream in){
this.in = in;
}
//一次读一个字节,从缓冲区(字节数组)获取。
public int myRead()throws IOException{//返回的是int类型为什么?? 类型提升了,
//通过in对象读取硬盘上数据,并存储buf中
if(count==0){//当数组中的数据都取光时,在抓一批数据。
count = in.read(buf);
if(count<0)
return -1;
pos = 0;
byte b = buf[pos];
count--;
pos++;
return b&255;
}else if(count>0){
byte b = buf[pos];
count--;
pos++;
return b&0xff;
}
return -1;
}
public void myClose()throws IOException{
in.close();
}
}
class FileOutputStreamDemo{
public static void main(String args[])throws IOException{
long start = System.currentTimeMillis();
copy_1();
long end = System.currentTimeMillis();
System.out.println((end-start)+"毫秒");//读的内容为-1,循环结束。
}
public static void copy_1() throws IOException{
MyBufferedInputStream bufis = new MyBufferedInputStream(new FileInputStream("d:\\11.mp3"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("d:\\22.mp3"));
int by = 0;
//System.out.println("第一个字节:"+bufis.myRead());
while((by=bufis.myRead())!=-1){
bufos.write(by);
}
bufos.close();
bufis.myClose();
}
}
//读取键盘录入,System.in:对应的是标准输出设备,,它一次只能读一个字节!!!!!!!!!!!
//控制台,System.in对应的是标准输入设备:键盘。
//read方法为一个阻塞方法,当没有读到的内容时,它会等待
import java.io.*;
class FileOutputStreamDemo{
public static void main(String args[])throws IOException{
InputStream in = System.in;
int by = in.read();//没有读到数据就会等。
int by1 = in.read();
System.out.println((char)by);
System.out.println(by1);
System.out.println('\r'+0);
System.out.println('\n'+0);
}
}
//当录入一行数据后,就将该行数据进行打印,如果录入的数据是
//read方法为一个阻塞方法,当没有读到的内容时,它会等待
//over,那么停止录入。
import java.io.*;
class FileOutputStreamDemo{
public static void main(String args[])throws IOException{
InputStream in = System.in;
StringBuilder sb = new StringBuilder();
while(true){
int ch = in.read();
if(ch=='\r')
continue;
if(ch=='\n'){
String s = sb.toString();
if("over".equals(s))
break;
System.out.println(s.toUpperCase());
sb.delete(0,sb.length());//清空缓冲区中的数据。
}else{
sb.append((char)ch);
}
}
}
}
//通过刚才的键盘录入一行数据并打印其大写,发现其实就是读
//一行数据的原理,也就是readLine方法,能不能直接使用readLine
//方法来完成键盘录入的一行数据的读取呢?readLine方法是字符
//流BufferedReader类中的方法,而键盘录入的read方法是字节流InputStream的方法。
//那么能不能将字节流转成字符流在使用字符流缓冲区的readLine方法呢?
//InputStreamReader是字节流通向字符流的桥梁,它本身是一个字符流对象,
//在构造时,需要传入一个字节流对象,
import java.io.*;
class FileOutputStreamDemo{
public static void main(String args[])throws IOException{
//获取键盘录入对象
InputStream in = System.in;
//将字节流对象转成字符流对象,使用转换流,InputStreamReader
InputStreamReader isr = new InputStreamReader(in);
//为了提高效率,将字符串进行缓冲区技术高效操作,使用BufferedReader
BufferedReader bufr = new BufferedReader(isr);
//将字符变成字节写入到文件中。
OutputStreamWriter osw = new OutputStreamWriter(System.out);
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
//System.out.println(line.toUpperCase());
osw.write(line.toUpperCase());
osw.flush();
}
bufr.close();
}
}
//读取键盘录入,System.in:对应的是标准输出设备,,它一次只能读一个字节!!!!!!!!!!!
//OutputStreamWriter是字符流通向字节流的桥梁,是Writer的子类,
// 我录入的是字符,存时,是字节,,在构造时,需要接收一个输出流对象。
//键盘录入最觉的写法。
//BufferedReader bufr =new BufferedReader(new InputStreamReader(System.in));
//BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
import java.io.*;
class FileOutputStreamDemo{
public static void main(String args[])throws IOException{
//获取键盘录入对象
InputStream in = System.in;
//将字节流对象转成字符流对象,使用转换流,InputStreamReader
InputStreamReader isr = new InputStreamReader(in);
//为了提高效率,将字符串进行缓冲区技术高效操作,使用BufferedReader
BufferedReader bufr = new BufferedReader(isr);
//字符流通向字节流的桥梁,
OutputStream out = System.out;
OutputStreamWriter osw = new OutputStreamWriter(out);//装饰设计
BufferedWriter bufw = new BufferedWriter(osw);//装饰设计,功能增强。
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();//功能的增强
bufw.flush();//用到了字符流的缓冲区,需要刷新。
}
bufr.close();
}
}
//需求:想把键盘录入的数据存储到一个文件中。源:键盘,目的:文件。
import java.io.*;
class FileOutputStreamDemo{
public static void main(String args[])throws IOException{
//键盘的最常见写法。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("111111.txt")));
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();//换行。
bufw.flush();
}
}
}
//需求:想要把一个文件的数据打印在控制台上。源:文件,目的:控制台
import java.io.*;
class FileOutputStreamDemo{
public static void main(String args[])throws IOException{
BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("FileOutputStreamDemo.java")));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String str = null;
while((str=bufr.readLine())!=null){
if("over".equals(str))
break;
bufw.write(str.toUpperCase());
bufw.newLine();
}
bufw.close();
}
}
//通过三个明确来完成。
1 ,明确源和目的。
源:输入流。 InputStream Reader
目的:输出流 OutputStream Writer
2 ,明确操作的数据是否是纯文本。
是:字符流
否:字节流
3 ,当体系明确后,在明确要使用哪个具体的对象
通过设备来进行区分:
源设备:内存、硬盘、键盘;
目的设备:内存、硬盘、控制台;
一,将一个文本文件中的数据存储到另一个文件中,复制文件。
源:因为是源,所以使用读取流。 InputStream Reader
是不是操作文本文件。
是!就可以选择Reader
这样体系就明确了。
接下来明确使用该体系中的哪个对象。
明确设备:硬盘,上一个文件。
Reader 体系中可以操作文件的对象是FileReader.
是否需要提高效率:是,加入Reader体系中的缓冲区,BufferedReader
FileReader fr = new FileReader("a.txt");
BufferedReader bufr = new BufferedReader(fr);
目的:OuputStream Writer
是否是纯文本。
是!Writer
设备:硬盘,一个文件。
Writer 体系中可以操作文件的对象FileWriter
是否需要提高效率:是,加入Writer体系中缓冲区 BufferedWriter
FileWriter fw = new FileWriter("b.txt");
BufferedWriter bufw = new BufferedWriter(fw);
练习:将一个图片文件中数据存储到另一个文件中,复制文件。要按照以上格式。
2 ,需求:将键盘录入的数据保存到一个文件中。
这个需求中有源和目都存在。
是不是纯文本?是Reader
设备:键盘,对应的对象是System.in.
不是选择Reader吗?System.in对应的不是字节流吗?
为了操作键盘的文本数据方便,转成字符流按照字符串操作是
最方便的。所以既然明确了Reader,那么就将System.in转换成Reader.
用了Reader体系中的转换流,InputStreamReader.
InputStreamReader isr = new InputStream(System.in);
需要提高效率吗?需要,BufferedReader
BufferedReader bufr = new BufferedReader(isr);
目的:OutputStream Writer
是否是纯文本:是!Writer
设备:硬盘,一个文件,使用FileWriter
FileWriter fw = new FileWriter("c.txt");
需要提高效率吗?需要。
BufferedWriter bufw = new BufferedWriter(fw);
************************
扩展一下,想要把录入的数据按照指定的编码表(utf-8),将
数据存入到文件中。
目的:OutputStream Writer
是否是纯文本?是Writer
设备:硬盘:一个文件,使用FileWriter
但是FileWriter是使用的默认编码表。GBK
但是存储时,需要加入指定编码表utf-8,而指定的编码表只有
转换流可以指定。所以要使用对象是OutputStreamWriter
而该转换流对象要接收一个字节输出流,而且还可以操作文件
的字节输出流,FileOutputStream.
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"utf-8");
需要高效吗?需要
BufferedWriter bufw = new BufferedWriter(osw);
所以,记住,转换流什么时候使用,是字符和字节之间的桥梁,
通常,涉及到字符编码转换时,需要用到转换流。
将一个文件数据打印在控制台上,按照以上格式。
//文件复制的另一个方式。
import java.io.*;
class FileOutputStreamDemo{
public static void main(String args[])throws IOException{
System.setIn(new FileInputStream("FileOutputStreamDemo.java"));
System.setOut(new PrintStream("zzz.txt"));
//键盘最常见的写法。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close();
}
}
//异常信息
//日志信息的建立:log4j工具。
// void printStackTrace(PrintStream s) 将此 throwable 及其追踪输出到指定的输出流。
import java.io.*;
import java.util.*;
import java.text.*;
class FileOutputStreamDemo{
public static void main(String args[])throws IOException{
try
{
int[] arr = new int[2];
System.out.println(arr[3]);
}
catch (Exception e)
{
//e.printStackTrace(System.out);//System.out是PrintStream的对象。
//e.printStackTrace(new PrintStream("a.txt"));//目的变成了文件。
try
{
Date d = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = sdf.format(d);
PrintStream ps = new PrintStream("exeception.log");
//ps.write(d.toString().getBytes());
ps.println(s);
System.setOut(ps);
}
catch (IOException ex)
{
throw new RuntimeException("日志文件创建失败。");
}
e.printStackTrace(System.out);
}
}
}
*/
import java.io.*;
import java.util.*;
class FileOutputStreamDemo{
public static void main(String args[])throws IOException{
Properties prop = System.getProperties();
prop.list(new PrintStream("Sysinfo.txt"));
//prop.list(System.in);
}
}
//一次读一个字节,从缓冲区(字节数组)获取,模拟一个BufferedInputStream。
class FygException7{
public static void main(String args[])throws Exception{
long start = System.currentTimeMillis();
copy_1();
long end = System.currentTimeMillis();
}
public static void copy_1()throws Exception{
MyBufferedInputStream mbi = new MyBufferedInputStream(new FileInputStream("d:\\110.jpg"));
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("d:\\333.jpg"));
int ch = 0;
while((ch=mbi.myRead())!=-1){
out.write(ch);
}
out.close();
mbi.close();
}
}
class MyBufferedInputStream{
private byte[] buf = new byte[1024];
private int len = 0,pos = 0;
private InputStream r;
//private byte b;
MyBufferedInputStream(InputStream r){
this.r = r;
}
public int myRead()throws Exception{
/*
if(len>0){
byte b = buf[pos];
pos++;
len--;
return b&255;
}else if(len==0){
len = r.read(buf);
if(len<0)
return -1;
pos=0;
byte b = buf[pos];
pos++;
len--;
return b&255;
}
return -1;
*/
if(len==0){//当数组中的数据都取光时,在抓一批数据。
len = r.read(buf);
if(len<0)
return -1;
pos = 0;
byte b = buf[pos];
len--;
pos++;
return b&255;
}else if(len>0){
byte b = buf[pos];
len--;
pos++;
return b&0xff;
}
return -1;
}
public void close()throws Exception{
r.close();
}
}