IO流、字节输入输出流、字符输入输出流
IO概述
I:input
O:output
流:数据传输(字符、字节)
IO根据数据的流向分为输入流、输出流(以内存为主体,数据流向硬盘为内存输出,数据流向内存为内存输入。)IO主要执行的操作为read-读取、write-写出(以内存为主体,读取是内存读取硬盘数据,写出是内存写出数据到硬盘)。
根据数据类型分为:字符流,字节流
输入流 | 输出流 | |
---|---|---|
字节流 | 字节输入流 InputStream | 字节输出流 OutputStream |
字符流 | 字符输入流 Reader | 字符输出流 Writer |
java.io.OutputStream字节输出流
java.io.OutputStream字节输出流,抽象类,其子类共性成员方法有:
1.void close()关闭并释放资源
2.void flush()刷新此输出流并强制任何缓冲的输出字节被写出
3.void write(byte[] b)把字节数组写入此输出流
4.void write(byte[] b,int off,int len)把字节数组从偏移量off开始的len长度数组,写入此输出流
5.void write(int b)把指定的字节输出流
子类java.io.FileOutputStream
文件字节输出流,把内存中的数据写入到硬盘的文件中
构造方法:
1.FileOutputStream(String name,(可写可不写参数)boolean append)
2.FileOutputStream(File file,(可写可不写参数)boolean append)
在指定路径创建文件
boolean append为true时,创建文件不会覆盖原文件,而是在原文件基础上追加写入输出流。
写入数据的原理(内存–>硬盘):
java程序–>JVM–>OS(操作系统)–>OS调用写数据的方法–>把数据写入到文件中
换行符号:
windows:\r\n
linux:/n
mac:/r
使用方法eg:
public static void main(String[] args) {
File file = new File("abc.txt");
//1.创建对象new FileOutputStream
try {
FileOutputStream fileOutputStream = new FileOutputStream(file,true);
//2.write写出数据
String str = "aiuvibbkjbebashbuucjkndsafybube";
byte[] bytes = str.getBytes();//中文一个字的GBK编码是两个字节,并且第一个字节是负数
fileOutputStream.write(bytes);
fileOutputStream.write("\r\n".getBytes());
fileOutputStream.write(bytes,10,10);
//3.释放资源
fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
java.io.InputStream字节输入流
java.io.InputStream,字节输入流,抽象类,其子类共性成员方法有:
1.void close()关闭并释放资源
2.int read()从输入流中读取【下】一字节,并返回【这个字节】
3.int read(byte[] b)从输入流中读取一定数量的字节,并存储在缓冲区数组b中,返回值为读取有效个数的长度,即修改了缓冲区byte[]中的前几个元素(如果循环读取到结尾,后面的元素是没有被修改的),如果返回值为-1,则说明一个也没修改。
子类java.io.FileInputStream
文件字节输入流,把硬盘文件中的数据读取到内存中使用
构造方法:
1.FileInputStream(String name)
2.FileInputStream(File file)
另:字节流使用GBK编码,两个byte组合为一个汉字字符,而java控制台使用UTF-8编码,三个byte组合成一个汉字字符,所以在控制台打印输出汉字时会出现乱码。这时,使用字符流好一些。
按理说是1 char = 2 byte,1 byte = 8bit。但是汉字字符在不同编码格式下有不同的表现形式。
使用方法eg:
public static void main(String[] args) throws IOException {
File file = new File("abc.txt");
//1.创建对象new FileInputStream
FileInputStream fileInputStream = new FileInputStream(file);
//2.创建字节数组缓冲区
byte[] b = new byte[20];//创建缓冲区数组b,常用长度1024或其整数
//3.read读取数据
int read = fileInputStream.read(b);
System.out.println(read);
System.out.println(new String(b));
//再读取一次,read2为读取有效个数的长度,注意此时指针已经在第21个字节
int read2 = fileInputStream.read(b);
System.out.println(read2);
System.out.println(new String(b));
//4.释放资源
fileInputStream.close();
}
java.io.Reader字符输入流
java.io.Reader,字符输入流,是字符输入流的最顶层父类,抽象类,其子类共性成员方法有:
(与字节流类似)
1.void close()关闭并释放资源
2.int read()从输入流中读取【下】一字字符,并返回。
3.int read(char[] cbuf)从输入流中读取一定数量的字符,并存储在数组cbuf中。返回值为这次修改了数组中的多少元素,没有修改返回-1。
子类java.io.FileReader extends InputStreamReader extends Reader
文件字符输入流,把硬盘文件中的数据以字符的方式,读取到内存中使用
构造方法:
1.FileReader(String name)
2.FileReader(File file)
使用方法eg:
public static void main(String[] args) throws IOException {
//1创建对象new FileReader
FileReader fileReader = new FileReader("f:\\a.txt");
//2.新建字符数组缓冲区
char[] chars = new char[1024];
//3.读取数据
int len = fileReader.read(chars);
int len2 = fileReader.read(chars);
System.out.println(len2);
System.out.println(new String(chars));
//4释放资源
fileReader.close();
}
java.io.Writer字符输出流
java.io.Writer,字符输出流,所有字符输出流最顶层父类,抽象类,其子类共性成员方法有:
(与字节输出流类似)
1.void close()关闭并释放资源,但要先 刷新 它
2.void flush()刷新此输出流并强制任何 【缓冲的】 输出字符被写出
3.void write(char[] cbuf)写入字符数组到内存缓冲区
4.void write(char[] cbuf,int off,int len)把字符数组从偏移量off开始的len长度数组,写到内存缓冲区
5.void write(int c)写入单个字符到内存缓冲区
6.void write(String str)写入字符串到内存缓冲区
7.void write(String str,int off,int len)把字符串从偏移量off开始的len长度数组,写到内存缓冲区
子类java.io.FileWriter extends OutputStreamWriter extends Writer
文件字符输出流,把内存中的字符数据写入到硬盘的文件中
构造方法:
1.FileWriter(String name,(可写可不写)boolean append))
2.FileWriter(File file,(可写可不写boolean append))
在指定路径创建文件
boolean append为true时,不会创建文件覆盖原文件,而是在原文件基础上追加写入输出流。
写入数据的原理(内存–>硬盘):
java程序–>JVM–>OS(操作系统)–>OS调用写数据的方法–>把数据写入到文件中
换行符号:
windows:\r\n
linux:/n
mac:/r
使用方法eg:
public static void main(String[] args) throws IOException {
//1.创建对象
FileWriter fileWriter = new FileWriter("f:\\b.txt");
//2.写出到内存缓冲区,内存把字符变为字节
fileWriter.write(97);
//3.刷新
fileWriter.flush();
//4.关闭资源
fileWriter.close();
}
public static void main(String[] args) throws IOException {
//1.创建对象
FileWriter fileWriter = new FileWriter("f:\\c.txt");
//2.写出到内存缓冲区,内存把字符变为字节
char[] chars = {'a', 'b','c', 'd', 'e'};
fileWriter.write(chars);//abcde
fileWriter.write(chars,2,3);//cde
String str ="def";
fileWriter.write(str);//def
fileWriter.write(str,0,2);//de
//3.刷新
fileWriter.flush();
//4.释放资源
fileWriter.close();
}
注意:输入流与输出流的创建与使用都是有异常的,实际应用中我们应该try…catch,而不是抛出:
在JDK1.7之前,使用try…catch时注意点有四:
public static void main(String[] args) {
//1.把FileWriter对象的作用域上升在try之前
//2.FileWriter对象必须赋值为null
FileWriter fileWriter = null;
try{
fileWriter = new FileWriter("f:\\b.txt");
fileWriter.write(97);
fileWriter.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
//3.在finally中释放资源,而且要try..catch
//4.加if判断语句fileWriter不为空时才释放资源
if (fileWriter !=null) {
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
在JDK1.7之后,使用try…catch时,try(){}括号中定义流对象,执行完毕try,自动释放括号中的对象,不用写finally:
//文件拷贝案例
public static void main(String[] args) {
try(
FileInputStream source = new FileInputStream("E:\\Capture001.png");
FileOutputStream target = new FileOutputStream("F:\\a.png");
){
byte[] bytes = new byte[1024];
int len = 0;
while ((len = source.read(bytes)) !=-1) {//注意判断方法
target.write(bytes);
}
/*//释放资源(先关闭输出流较好,原则先开后关)
target.close();
source.close();*/
}catch (IOException e) {
e.printStackTrace();
}
}
在JDK1.9之后,使用try…catch时,try(){},try前定义定义流对象,括号中传参数,执行完毕try,自动释放括号中的对象,不用写finally
//文件拷贝案例
public static void main(String[] args) throws FileNotFoundException {
FileInputStream source = new FileInputStream("E:\\Capture001.png");
FileOutputStream target = new FileOutputStream("F:\\a.png");
try(source;target){
byte[] bytes = new byte[1024];
int len = 0;
while ((len = source.read(bytes)) !=-1) {
target.write(bytes);
}
/*//释放资源(先关闭输出流较好)
target.close();
source.close();*/
}catch (IOException e) {
e.printStackTrace();
}
}
双列集合Properties
java.util.Properties extends hashtable<k,v> implements Map<k,v>
Properties是唯一和IO流结合的双列集合
方法store()输出(写出)数据
方法load()输入(读取)数据
Properties集合的key和value都默认为字符串
eg1:Properties的基本使用
public static void main(String[] args) {
//1.创建对象new Properties,默认都为String
Properties properties = new Properties();
//2.setProperty方法,添加键值对
properties.setProperty("阿明","15");
properties.setProperty("阿花","14");
properties.setProperty("阿拉","17");
properties.setProperty("阿奔","25");
//3.stringPropertyNames方法,取出key组成Set集合
Set<String> strings = properties.stringPropertyNames();
//4.getProperty得到key对应的value值
for (String string : strings) {
String value = properties.getProperty(string);
System.out.println(string +"="+value);
}
}
eg2:Properties输出键值对
方法:
void store(OutputStream out ,String comments)字节输出流不能有中文
void store(Writer writer ,String comments)字符写出流可以有中文
注意: comments注释不能为中文
public static void main(String[] args) throws IOException {
//void store(OutputStream out ,String comments)字节输出流不能有中文
//void store(Writer writer ,String comments)字符写出流可以有中文
// comments注释不能为中文
//1.创建对象
Properties properties = new Properties();
//2.添加键值对
properties.setProperty("阿明","15");
properties.setProperty("阿花","14");
properties.setProperty("阿拉","17");
properties.setProperty("阿奔","25");
//3.创建FileWriter对象
FileWriter fileWriter = new FileWriter("f:\\a.txt");
//4.store方法,输出键值对
properties.store(fileWriter,"name=age");
//5.释放资源
fileWriter.close();
}
eg3:Properties读取键值对
方法:
void load(InputStream inStream )字节输入流不能有中文
void load(Reader reader)字符读取流可以有中文
注意:
1.文件中键值对默认连接符号可以用=,空格(其他符号)
2.文件中可以用#进行注释,被注释的键值对不会再被读取
public static void main(String[] args) throws IOException {
//void load(InputStream inStream )字节输入流不能有中文
//void load(Reader reader)字符读取流可以有中文
//注意:1.文件中键值对默认连接符号可以用=,空格(其他符号)2.文件中可以用#进行注释,被注释的键值对不会再被读取
//1.创建对象
Properties prop = new Properties();
//2.创建对象
FileReader fileReader = new FileReader("f:\\a.txt");
//3.load方法,读取键值对到Properties对象
prop.load(fileReader);
//4.释放资源
fileReader.close();
Set<String> strings = prop.stringPropertyNames();
for (String string : strings) {
String property = prop.getProperty(string);
System.out.println(string+"="+property);
}
}