------- android培训、java培训、期待与您交流! ----------
IO操作
即对输入与输出的操作,通过面向对象的思想把输入与输出的数据的过程转为对流对象(IO流)的操作,简化了对数据操作的复杂度。
通过对流的共性的总结,可以获得四类基本抽象流类型:
输入字节流:InputStream
输入字符流:Reader
输出字节流:OutputStream
输出字符流:Writer
同异常一样,他们的子类的名字大多数是用父类坐为后缀。
字节:即存储在电子设备中最基本的数据单元,可以理解为一个小盒子byte,多个盒子组合在一起成为一个字符。所以处理字节或二进制对象时使用字节流。(8bits=1byte)未使用缓冲区。
字符:即人类可以认知的最基本的单元。比如一个文字,一个字母等,是字节与编码表的组合。处理文字时使用字符流。使用了缓冲区提高效率,要输出就要刷新缓冲区。
编码表:即字符与字节的对应关系表,国际上有不同的编码表:
ASCII:美国标准信息交换码
GB2312:中文编码表。
GBK:融合了更多的中文文字符号,是中国的中文编码表升级版。
Unicode:国际标准码,所有文字都用两个字节来表示,java使用的就是unicode。
UTF-8:最多用三个字节来表示一个字符,使用方便。
编码:字符串变成字节数组:str.getBytes(charsetName);
解码:字节数组变成字符串:newString(byte[].charsetName);
对流的操作
Eg:
//IO操作常常会伴随着异常的出现,所以必须抛出或try,多数情况下应该try。
try(InputStream is = new FileInputStream(src);
OutputStream os = newFileOutputStream(tar);)
//第一步的建立输入输入流对象。
{
byte[] b = newbyte[1024];//建立缓冲区提高效率。
int len;
while ((len = is.read(b)) != -1) //先读取数据
{
os.write(b);//后写入数据
}
}
catch (IOException e)
{
e.printStackTrace();
}
注意:()圆括号内创建的对象必须实现Autocloseable接口,从而对象可以自动关闭资源。
Eg:
public static void copy
{
FileWriter fw = null;
FileReader fr = null;
char[] buf = new char[1024];intlen = 0;
while((len=fr.read(buf))!=-1)
{
fw.write(buf,0,len);
}
}catch(IOException e)
{
throw new RuntimeException(“读写出现问题,请测试”);
}finally
{
if(fr!=null)
try
{
fr.close();
}catch(IOException e){}
if(fw!=null)
try
{
fw.close();
}catch(IOException e){}
}
}
Eg:复制图片:
图片》》字节流
public class Demo
{
public static void main(String[]args) throws Exception
{
File src = newFile("E:/java.jpg");
File tar = newFile("E:/tar.jpg");
copy(src,tar);
System.out.println("复制完成!");
}
public static void copy(Filesrc,File tar) throws Exception
{
//流对象的创建
InputStream in = newFileInputStream(src);
OutputStream os = newFileOutputStream(tar);
//缓冲区的建立
byte []c = new byte[1024];
int len;
//数据的读取
while((len = in.read(c)) !=-1)
{//数据的存入
os.write(c);
}
//资源的关闭。对于字节流可以不操作,但是养成习惯有必要。
w.close();
r.close();
}
}
缓冲字符流:
缓冲区的出现提高了对数据的读写效率。
BufferedWriter
BufferedReader
Eg:
FileWriter fw = new FileWriter(“demo.txt”);
BufferedWriterbufw = new BufferedWriter(fw); //创建文件字符写入流的缓冲与流对象关联
bufw.write(“asdfg1234”);//数据进入缓冲区
bufw.flush();//使用缓冲区的刷新方法将数据刷到目的地
bufw.close();//关闭缓冲区也关闭了流资源
对于缓冲读取流,具有readline方法方便了对文本文件的的读取。
String s = bufr.readLine();
读取一行并保存在字符串s中,到末尾返回null。事实上市read的原理的修饰版。原理如下:
public String myReadLine() throws IOException
{
StringBuilder sb = newStringBuilder();//字符串容器
int ch = 0;
while((ch=r.read())!=-1)
{
if(ch==’\r’)
continue;
if(ch==’\n’)
return sb.toString();
else
sb.append((char)ch);
}
if(sb.length()!=0)
return sb.toString();
return null;
}
public void myClose() throws IOException
{
r.close();
}
拓展:
装饰模式:
如把read装饰成为realine一样,与继承一样的功能,装饰设计模式通过把原有的类,功能进行不修改的拓展(重新创建一个类并引入要拓展的类进行修饰)。其中为了更强的功能,装饰类通常会通过构造方法接受被装饰的对象。
例如:Writer中用于操作文本TextWriter与用于操作媒体的MediaWriter都可以进行装饰后成为BufferTextWriter和BufferMediaWriter,同样是加入缓冲技术,那么直接引入BufferedWriter,在使用的时候对TextWriter嵌套进去进行装饰成为BufferedWriter(new TextWriter)即可,方便灵活。(假如是通过继承来达到同样的目的,那么继承体系将会很臃肿,不便于学习与升级)。
Eg:
LineNumberReader原理:
class MyLineNumberReader
{
private Reader r ;
private int lineNumber;
MyLineNumber(Reader r)// 通过构造方法接受被装饰的对象
{
this.r=r;
}
public String myReadLine()throws IOException //文本读取操作
{
lineNumber++;
StringBuilder sb = newStringBuilder();
int ch = 0;
while((ch=r.read())!=-1)
{
if(ch==’\r’)
continue;
if(ch==’\n’)
return sb.toString();
else sb.append((char)ch);
}
if(sb.length()!=0)
return sb.toString();
return null;
}
public void getLineNumber()//获取行数
{
Return lineNumber;
}
public void setLineNumber(intlineNumber)//设置行数
{
this.lineNumber = llineNumber;
}
public void myClose()
{
r.close();//关闭流
}
}
:
字节流:
当要操作图片,字节码数据时要用到字节流。
InputStream
OutputStream
Eg:
public static void writeFile() throws IOException
{
FileOutputSream fos = newFileOutputStream(“fos.txt”);
fox.write(“asfdsdgjh”.getBytes());//字符串变成字节数组
fos.close();//不需要flush()。
}
Eg:
public static void readFile() throws IOException
{
FileInputSream fis = new FileInputStream(“fos.txt”);
Byte[] buf = new byte[1024];//一次读取多个字节,但可能会溢出数据。
// byte[] buf = newbyte[fis.available()];//一次读取刚好不会溢出的多个字节。
int len = 0;
While((len=fis.read(buf))!=-1)
{
System.out.println(newString(buf,0,len));
}
fis.close();
}
缓冲字节流:
与缓冲字符流效果一样。
BufferedOutputStream
BufferedIntputStream
Eg:
class MyBuffereInputStream//装饰类
{
private InputStream in;
private byte[] buf = newbyte[1024*4];
Private int pos=0,count=0;
MyBuffereInputStream(InputStream in)
{//通过in对象读取硬盘上数据,并存储buf中。
this.in= in;
}
public int myRead() throwsIOException
{//一次读一个字节,从缓冲区获取。
if(count==0)
{
count=in.read(buf);
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()throwsIOException
{
in.close();
}
}
字节字符转换流
可以把字节流转换为字符流,以方便使用字符流的方法。
OutputStreamWriter:把字节输出流对象转成字符输出流对象
InputStreamReader:把字节输入流对象转成字符输入流对象
提供了最长用的获取键盘输入的方法:
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(newOutputStreamWriter(System.out));
文本--->控制台
BufferedReader bufr = new BufferedReader(new InputStreamReader(newFileInputStream(“1.txt”)));
BufferedWriter bufw = new BufferedWriter(newOutputStreamWriter(System.out));
控制台-->文本
BufferedReader bufr = new BufferedReader(newInputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(newFileOutputStream(”demo.txt”)));
Eg:
InputStream is = new FileInputStream("");//构建一个字节输入流对象
Reader r = new InputStreamReader(is); //把字节输入流转成字符输入流
内存操作流
当输出的数据进入内存,使用内存操作流,以提升性能。
ByteArrayInputStream:写入内存 CharArrayReader
ByteArrayOutputStream:写出数据 CharArrayWriter
Eg:
String s = "String to be input";
//输出流的创建
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//写入内存中
bos.write(s.getBytes());
byte[] bys = bos.toByteArray();//读取的数据源
//创建输入流,明确源。
ByteArrayInputStream bis = new ByteArrayInputStream(bys);
byte[] b = new byte[1024];
int len;
while ((len = bis.read(b)) != -1) //读取数据
{
String data = new String(b,0, len);
System.out.println(data);
}
}
打印流
针对任意数据类型的操作所使用的类,比如操作字符串或者是boolean型或者是字符型
PrintWriter
PrintStream
注意:
1,在实例化的时候依然需要一个OutputStream的对象。
2,PrintStream和PrintWriter都属于输出流,分别针对字节和字符。,
3,PrintWriter和PrintStream重载的print()和println()用于多种数据类型的输出。其中print()里的参数不能为空;println()可以。
4,PrintStream调用println方法有自动flush功能;
5,PrintWriter和PrintStream输出操作不抛出异常;
6,格式化输出操作使用printf()方法,需要指定输出数据的类型:
String format = "姓名=%s,学号=%s,年龄=%d,成绩=%f";
System.out.printf(format,name,num,age,score);
Eg:
// 创建字符打印流
PrintWriter pr = new PrintWriter(new FileWriter("out.txt"),true);//必须调用println,print,format这些方法的其中一个才可以实现操作自动刷新
pr.println("我是输入的内容");
pr.println(true);
pr = new PrintWriter(System.out, true);
pr.println(3dfsfsfsd234535);
标准流
标准输入流,默认表示的是键盘录入: System.in
标准输出流,默认表示的是屏幕输出: System.out
改变默认值:
System.setIn(new FileInputStream("demoA"));//改变默认打印源
System.setOut(new PrintStream("demoB.txt"));//改变默认打印目的地到文件中
文本扫描器Scanner
Eg:
Scanner sc = new Scanner(System.in);
while(sc.hasNext())
{
String s = sc.next();
System.out.println(s);
}
合并流
用于将两个流进行合并:SequenceInputStream(InputStream s1, InputStream s2) ,根据两个流对象来创建合并流对象,FIFO。
Eg:
public static void main(String[] args) throws IOException
{
SequenceInputStream si = newSequenceInputStream(
newFileInputStream("6.4"),
newFileInputStream("hello.java"));
OutputStream os = newFileOutputStream("sequence.txt");
int len;
byte []b = new byte[1024];
while((len = si.read(b)) !=-1)
{
os.write(b, 0, len);
}
}
流操作的基本规律总结:
1,明确体系: 数据源:InputStream,Reader
数据汇:OutputStream,Writer
2,明确数据:数据分两种:字节,字符。
数据源:是否是纯文本数据呢?是:Reader 否:InputStream
数据汇:是:Writer 否:OutputStream
到这里就可以明确具体要使用哪一个体系了。
接下来要明确使用这个体系中的哪个对象。
3,明确设备:
数据源: 键盘:System.in
硬盘:FileXXX
内存:数组。
网络:socket socket.getInputStream();
数据汇: 控制台:System.out
硬盘:FileXXX
内存:数组
网络:socketsocket.getOutputStream();
4,明确额外功能: 1,需要转换?是,使用转换流。InputStreamReader OutputStreamWriter
2,需要高效?是,使用缓冲区。Buffered
3,需要其他?
复制一个文本文件:
1,明确体系: 源:InputStream ,Reader
目的:OutputStream,Writer
2,明确数据: 源:是纯文本吗?是 Reader
目的;是纯文本吗?是Writer
3,明确设备: 源:硬盘上的一个文件。 FileReader
目的:硬盘上的一个文件。FileWriter
FileReader fr = newFileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
4,需要额外功能吗?需要,高效,使用buffer
BufferedReader bufr = newBufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = newBufferedWriter(new FileWriter("b.txt"));
读取键盘录入,将数据存储到一个文件中:
1,明确体系: 源:InputStream ,Reader
目的:OutputStream,Writer
2,明确数据: 源:是纯文本吗?是 Reader
目的;是纯文本吗?是Writer
3,明确设备: 源:键盘,System.in
目的:硬盘,FileWriter
InputStream in =System.in;
FileWriter fw = newFileWriter("a.txt");
4,需要额外功能吗?
需要,因为源明确的体系是Reader。可是源的设备是System.in。
所以需要转换流。InputStreamReader
InputStreamReader isr = newInputStreamReader(System.in);
FileWriter fw = new FileWriter("a.txt");
需要高效用:
BufferedReader bufr = new BufferedReader(newInputStreamReader(System.in));
BufferedWriter bufw = newBufferedWriter(new FileWriter("a.txt"));
读取一个文本文件,将数据展现在控制台上:
1,明确体系: 源:InputStream ,Reader
目的:OutputStream,Writer
2,明确数据: 源:是纯文本吗?是 Reader
目的;是纯文本吗?是Writer
3,明确设备: 源:硬盘文件,FileReader。
目的:控制台:System.out。
FileReader fr = newFileReader("a.txt");
OutputStream out =System.out;
4,需要额外功能?
需要一个转换流,OutputStreamWriter
FileReader fr = newFileReader("a.txt");
OutputStreamWriter osw =new OutputStreamWriter(System.out);
需要高效
BufferedReader bufr = new BufferedReader(newFileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(newOutputStreamWriter(System.out));
读取键盘录入,将数据展现在控制台上:
1,明确体系: 源:InputStream ,Reader
目的:OutputStream,Writer
2,明确数据: 源:是纯文本吗?是 Reader
目的;是纯文本吗?是Writer
3,明确设备: 源:键盘:System.in
目的:控制台:System.out
InputStream in =System.in;
OutputStream out =System.out;
4,需要额外功能,使用转换流。
为了提高效率,使用Buffer
BufferedReader bufr =newBufferedReader(new InputStreamReader(Systme.in));
BufferedWriter bufw = new BufferedWriter(newOutputStreamWriter(System.out));
读取一个文本文件,将文件按照指定的编码表UTF-8进行存储,保存到另一个文件中:
1,明确体系: 源:InputStream ,Reader
目的:OutputStream,Writer
2,明确数据: 源:是纯文本吗?是 Reader
目的;是纯文本吗?是Writer
3,明确设备: 源:硬盘:FileReader.
目的:硬盘:FileWriter
FileReader fr = newFileReader("a.txt");
FileWriter fw = newFileWriter("b.txt");
4,额外功能:
需要指定编码表,需要转换功能OutputStreamWriter使用字节输出流中的操作文件的流对象FileOutputStream。
FileReader fr = newFileReader("a.txt"); OutputStreamWriterosw = new OutputStreamWriter(new FileOutputStream("demo.txt"),"UTF-8");
需要高效
BufferedReader bufr = newBufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = newBufferedWriter(new OutputStreamWriter(new FileOutputStream("demo.txt"),"UTF-8"));