黑马程序员-第十九天( IO(Input Output)流)

---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------

                                                            IO(Input Output)流


一、IO流作用
IO流用来处理设备之间的数据传输
java对数据的操作是通过流的方式
java用于操作流的对象都在IO包中

二、流的分类
流按操作数据分为两种:字节流和字符流。字节流可以融入编码表,可以自己指定编码表。字节流是通用的,字符流是基于字节流的。
流按流向分为:输入流和输出流。 

三、编码表
ASCII(一个字节):美国编码表
GBK(两个字节):中国编码表
UnCode(两个字节表示):国际编码表  后来优化成UTF-8(所占字节自动分配)      

乱码:一个格式的编码方式进行存储,然后以另一种编码方式进行读取,这样会导致乱码                                      


四、IO流常用基类
·字节流的抽象基类:
InputStream (读)  OutputStream(写)
·字符流的抽象基类:
Reader(读)  Writer(写)   

注: 由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。前缀名是对象的功能。如:
InputStream 的子类 FileInputStream
Reader 的子类 FileReader。


五、FileWriter

1,方法 (这些方法都会抛出IOException异常):
void writer(int ch);写入单个的字符            
void writer(char[] arr);写入一个字符数组 
void writer(char[] ,int off,int len);将指定字符数组中的一部分进行写入
void writer (String str);写入一个字符串
vois writer (String str,int off,int len);将字符串的指定部分进行写入
void flush()刷新该流的缓冲
void close()关闭此流,但要先刷新它(其实就是先调用flush()方法刷新一次,然后又调用底层关闭流的方法)

既然IO流是用于操作数据的,那么数据的最常见体现形式是:文件。

2,子类 FileWriter
创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件,而且该文件会被创建到指定目录下,
如果该目录下已有同名文件,将被覆盖。
如:
1,FileWriter fileWriter = new FileWriter("Demo.txt");
jvm执行完此语句时,会在堆内存中建立一个FileWriter对象,并在当前目录下建立一个Demo.txt文件如果些文件存在
将会被覆盖。 其实该步就是在明确数据要存放的目的地 
2,调用write方法,将字符串写入到流中。
fileWriter.write("abcde");
3, 刷新流对象中的缓冲中的数据,将数据刷到目的地中
fileWriter.flush();
4,关闭流资源,但关闭之前会刷新一次内部的缓冲区中的数据,将数据刷到指定的位置 
fileWriter.close();


六,对IO异常的处理

对其进行捕捉和处理。如下程序:
public class FileWriterDemo{

public static void main(String[] args){

//在try外面建立对象的引用 
FileWriter fw = null;
try{

fw = new FileWriter("Test.txt");
fw.write("heihie");
}
catch(IOException io){

System.out.println(io);
}
//一定要执行的动作关闭资源
finally{

try{

if(fw != null)
fw.close();
}
catch(IOException io){

System.out.println(io);
}

}
}
}


七、文本数据的续写
构造函数:
FileWriter(String name,boolean apped):    根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。
当传递一个true参数,代表不覆盖已有的文件,并在已有文件的未尾处进行数据续写


换行: ·在window中换行用:\r\n (wind中的记事本只能识别\r\n) 
·在Linux中换行用:\n
 
八、文本文件读取方式:

1,Reader中的方法:
abstract void close():关闭该流并释放与之关联在所有资源
void mark(int readAheadLimit) 标记流中的当前位置
boolean markSupported()判断此流是否支持mark()操作
int read()读取单个字符。返回字符的ASCII值,如果已到达流的未尾时,则返回-1
int read(char[] buf)将字符读入数组
abstract int read(char[] buf,int off,int len)将字符读入数组的某一部分
int read(CharBuffer target) 将字符读入指定的字符缓冲区
boolean ready():判断是否准备读取此流
void reset():重置该流
long skip(long n)路过字符

注:read()方法一次读一个字符,而且会自动向下读
2,FileReader 
·构造函数 :
FileReader(String name)
FileReader(File file)
·建立读取流步骤

方法一(read()方法):
public static void main(String[] args){

//在try块的外面建立读取流的引用 
FileReader fr = null;

try{

//让读取流与一个文件进行关联
fr = new FileReader("hehe.txt");
int ch = 0;
//循环的来读取文件中的字符 
while((ch = fr.read()) != -1){

System.out.println((char)ch);
}
catch(FileNotFoundException ex){

System.out.println("没有找到要读取的文件");
throw new RuntimeException();
}
catch(IOException e){

throw new RuntimeException();
}
finalyy{

try{
//判断此引用是不是为空,如不为null关闭资源
if(fr != null)
fr.close();
}
catch(IOException io){

throw new RuntimeException("流资源关闭失败");
}
}
}
}
方法二,使用read(char[] buf)来读取
public static void readMethodTwo(){

FileReader fr = null;

try{
//与文件进行关联
fr =  new FileReader("Test.txt") ;
char[] buf = new char[1024];
int num = 0;
while((num = fr.read(buf)) != -1){

System.out.println(new String(buf,0,num)) ;
}

}
catch(IOException io) {

throw new RuntimeException("出问题") ;
}
finally{

try{
//先判断下是否为空,如不为空关闭流资源
if(fr != null)
fr.close();
}
catch(IOException io){

throw new RuntimeException();
}
}
}
3,复制的原理:
其实就是将某盘(c盘)下的文件数据存储到另一个盘(d盘)的一个文件中

步骤:
1,在d盘下创建一个文件,用于存储c盘文件中的数据。
2,定义读取流和c盘文件进行关联。
3,通过不断的读写完成数据的存储。
4,关闭流资源
 
九、字符流的缓冲区
1,缓冲区的出现提高了流对数据的读写效率,而出现的,所有在创建缓冲区之前,必须要先有流对象
2,对应类
BufferedWriter
中的newLine()是一个跨平台的换行符
BufferedReader
中的String readLine()读出一行数据 ,不会读取换行符的。

3,缓冲区的关闭其实就是关闭它所提高效率的流对象,

十,readLine的原理:
无论是读一行,获取读取多个字符,其实最终都是在在硬盘上一个一个读取。所以最终使用的还是read方法
一次读一个的方法,只过就是先存放在一个容器里,当读到换行符时,才会返回。

十一,LineNumberReader(BuffferedReader的子类)


1,此类是获取或设置行号的一个包装类
2,特有方法:
int getLineNumber():获取行号
void setLineNumber(int) :设置行号

十二,字节流
InputStream:字节读取流
OutputStream:字节写入流

1.OutputStream中的方法(不需要刷新)
void close();关闭此流关联的资源
void flush();刷新此输出流并强制写出所有缓冲的输出字节
void  write(byte[] byte);将byte数组定入此输出流。
void write(byte[]b,int off,int len);将指定byte数组中从偏移量off开始的len个字节写入此输出流
void write(int b)将指定的字节写入此输出流

2,InputStream中的方法:
int available(); 返回这个文件的大小。(\r\n占两个字节)可以根据返回值定义一个刚刚大小的数组(存放临时读取的字节)
int read();读取一个字节并返回
int read(byte[] byte):将字节读取到byte数组中返回读取的个数
3,字节流中的read方法返回值为什么不是byte类型?
因为字节流在读取数据时都是二进制的数据,有可能会读到连续8个1的情况,,这时程序会返回-1,也就是read方法结束的标志,如果返回是
int类型时,系统会自动进行类型提升但是,-1进行提升时还会是-1,所以这时为了保留原来的8位,,就要&255这样可以保留最低8位了,
而当写入一个字节时,,write方法会自动将int类型的数据强制转换成byte类型数据进行写入,所以复制后的文件大小不会改变。

4,BufferedInputStream中的read方法的原理?
BufferedInputStream中的read方法是利用传入的InputStream对象中的read方法将数据读到一个临时的数组中,然后,在从数组一个一个
的向外读取。也就是说调用传入对象 中的read方法将一个数据读取到指定的数组中的,然后在数组中一个一个的读取,当数组中的数据都
读完时,再去读取一批数据到数组中,如此循环。


十三,键盘录入


System.out:对应的是标准输出设备:控制台
System.in:对应的是标准输入设备:键盘

1,read方法是一种阻塞式方法。

2,转换流:
将字节流转换成字符流,在构造函数类型是字节流对象
InputStreamReader:
将字符流转换成字节流。
OutputStreamWriter:
3,代码:
package io;
import java.io.*;


public class KeyBoardInputDemo{

public static void main(String[] args){

inputDemo();
}
public static void inputDemo(){

BufferedReader bufr = null;

try{

bufr = new BufferedReader(new InputStreamReader(System.in)) ;

String str = null;

while((str = bufr.readLine()) != null){

if("over".equals(str))
break;

System.out.println(str.toUpperCase());
}
}
catch(IOException e){

throw new RuntimeException("键盘录入出问题了,");
}
finally{

try{

if(bufr != null)
bufr.close();
}
catch(IOException i){

throw new RuntimeException("关闭流失败!") ;
}
}

}
}
十三。流操作的规律:
通过三个明确来完成
1,明确源和目的:
源:  输入流   InputStream   Reader
目的:输出流   OutputStream  Writer

2,操作的数据是否是纯文本:
是:   字符流
不是: 字节流

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

4,是否需要提高效率?
是:加入缓冲技术

5,转换流什么时候使用?
转换流 是字符和字节之间的桥梁,通常,涉及到字符编码转换时,需要用到转换流

6,改变标准的输入输出设备:
System.setIn(InputStream in);
System.setOut(PrintStream  out)

---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章