一、IO流分类
IO流的分类
1). 按流的方向划分:
输入流
输出流
2). 按流的类型划分:
字节流
字节输入流:InputStream(抽象类)
FileInputStream:针对文件操作的字节输入流(读)
字节缓冲输入流(字节高效输入流):BufferedInpuStream
字节输出流:OutputStream(抽象类)
FileOutputStream:针对文件操作的字节输出流(写)
字节缓冲输出流(字节高效输出流):BufferedOutputStream
字符流:由于字节流操作文本文件的时候(一次读取一个字节的时候,将内容输出在控制台上:可能出现中文乱码)
所以才有了字符流!
字符输入流:Reader:读
字节输入流通向字符输入流的桥梁(转换输入流):InputStreamReader
为了书写简单:FileReader
字符缓冲输入流(字符高效输入流):BufferedReader
特有功能:String readLine() :一次读取一行
字符输出流:Writer:写
字节输出流流通向字符输出流的桥梁(转换输出流):OutputStreamWriter
为了书写简单:FileWriter
字符缓冲输出流(字符高效输出流):BufferedWriter
特有功能:
public void newLine():写入一个行的分隔(换行功能)
3). 字节流:
字节输出流:OutputStreamStream抽象类
提供具体的子类:FileOutputStream
使用步骤 :
1)创建一个文件输出流对象
2)写一些内容(输出到某个盘符下或者当前项目下)
3)释放资源:流资源(流的底层----->非Java语言实现:本地方法)
文件----->都是跟系统相关的(主机环境)
构造方法:
FileOutputStream(File file)
File file = new File(“a.txt”) ;
new FileOutputStream(file) ;
public FileOutputStream(String name) throws FileNotFoundException(推荐:因为参数可以直接指定一个路径)
举例:
public class FileOutputStreamDemo {
public static void main(String[] args) throws IOException {
//创建一个文件输出流对象
//抽象类多态
// OutputStream out = new FileOutputStream("fos.txt") ;
//具体类创建
FileOutputStream fos = new FileOutputStream("fos.txt") ; //调用系统资源 执行当前地址:文件fos.txt
//写
fos.write("hello,io".getBytes());
//释放资源:将当前系统资源指向的这个文件将它从内存中释放调用
fos.close() ;
}
}
4). 字节输出流:写的功能
public void write(int b) throws IOException:给当前字节输出流中写入一个字节
public void write(byte[] b) throws IOException:写入一个字节数组
public void write(byte[] b,int off,int len)throws IOException:写一个字节数组的一部分
参数2:从指定位置开始
参数3:指定长度
举例:
public class FileOutputStreamDemo2 {
public static void main(String[] args) throws IOException {
//创建一个输出流对象
FileOutputStream fos = new FileOutputStream("fos2.txt") ;
//public void write(int b) throws IOException:给当前字节输出流中写入一个字节
/* fos.write(97); //打开文件---这个字节就寻找对应的ASCII码表的值!
fos.write(65);
fos.write(48);*/
// public void write(byte[] b) throws IOException:写入一个字节数组
byte[] bytes = {97,98,99,101} ;
fos.write(bytes) ;
//public void write(byte[] b,int off,int len)throws IOException:写一个字节数组的一部分
fos.write(bytes,0,2);
//释放资源
fos.close() ;
}
}
构造方法
public FileOutputStream(String name,boolean append) throws FileNotFoundException
创建一个文件输出流对象,第二个参数为true,就是在文件字节末尾处追加!
如何现在将输出一句内容,换一行?
windows操作系统
换行符号"\r\n"
举例:
public class FileOutputStreamDemo3 {
public static void main(String[] args) throws IOException {
//创建一个文件输出流对象,开启文件末尾字节追加
FileOutputStream fos = new FileOutputStream("fos3.txt",true) ;
//for循环
for(int x = 0 ; x < 10 ; x ++){
fos.write(("hello"+x).getBytes());
//写入一个换行符号
fos.write("\r\n".getBytes());
}
//关闭资源
fos.close();
}
}
5). 流中加入异常操作:
解决方案---->try…catch…finally 标准格式
举例:
public class FileOutputStreamDemo4 {
public static void main(String[] args) {
//method1() ;
// method2() ;
method3() ;
}
//第三种方式:try...catch...finally
private static void method3() {
FileOutputStream fos = null ;
try {
fos = new FileOutputStream("fos4.txt") ;
fos.write("hello,i'm coming...".getBytes());
} catch (IOException e) {
e.printStackTrace(); //如果try有问题:代码追踪到源码中,并且有jvm将异常信息以及源码的错误行数都可以 控制台日志体现
}finally {
if(fos!=null){
//释放资源
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//第二种方式:try...catch...catch
private static void method2() {
//创建一个文件输出流对象
FileOutputStream fos = null;
try {
fos = new FileOutputStream("fos4.txt");
//写数据
fos.write("hello,JavaEE".getBytes());
//关闭资源
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//第一种方式:就是分别try...catch
private static void method1() {
//创建一个文件输出流对象
FileOutputStream fos = null ;
try {
fos = new FileOutputStream("fos4.txt") ;
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//写数据
try {
fos.write("hello,OutputStream".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
//释放资源
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
6). 抽象类:InputStream:表示字节输入流的所有类的超类
提供的针对文件操作的输入流:FileInputStream
使用步骤:
1)创建文件操作输入流对象
public InputStream()
2)通过 文件字节输入流对象,读取指定的文件中的内容
读取数据的功能:
public int read() throws IOException:一次读取一个字节
public int read(byte[] b) throws IOException: 读取一个字节数组,返回的是读取的实际字节数
public int read(byte[] b,int off,int len) throws IOException:读取一部分字节数组
3)释放资源
一次读取一个字节:
读取一些文件,中文会出现乱码,原因就是将实际的字节数强制转为char类型,
而中文在idea平台:utf-8格式:一个中文对应三个字节,和前面的英文拼接不到一起,就出现中文乱码
举例:
public class FileInputStreamDemo {
public static void main(String[] args) throws IOException {
//创建文件操作输入流对象
// FileInputStream fis = new FileInputStream("fis.txt") ;
//读取当前项目下的FileOutputStreamDemo
FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java") ;
//读
// public int read() throws IOException:一次读取一个字节
/* //第一次读
int by = fis.read();
System.out.println((char)by);
//第二次读
by = fis.read() ;
System.out.println((char)by);
//第三次读
by = fis.read() ;
System.out.println((char)by);
//第四次读
by = fis.read() ;
System.out.println((char)by);
//第五次读
by =fis.read() ;
System.out.println(by);
System.out.println((char)by);*/
//结束条件就是看返回结果为-1
//将上面的结果进行优化
/* int by = fis.read() ;//一次读取一个字节
while(by!=-1){
System.out.print((char)by);
by = fis.read() ;
}*/
//最终版代码
//将获取,判断,赋值直接一次性使用
//声明一个字节数
int by = 0 ;
while((by=fis.read())!=-1){
System.out.print((char)by);
}
//释放资源
fis.close();
}
}
7). public int read(byte[] b) throws IOException: 读取一个字节数组,返回的是读取的实际字节数
字节输入流 一次读取一个字节/一次读取一个字节数组 (第二种方式的读写速率优于第一种方式!)
举例:
public class FileInputStreamDemo2 {
public static void main(String[] args) throws IOException {
//创建一个字节输入流对象
// FileInputStream fis = new FileInputStream("fis2.txt") ;
FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java") ;
// public int read(byte[] b) throws IOException:
// 读取一个字节数组,返回的是读取的实际字节数
//定义一个字节缓冲区:长度5个
/* byte[] bytes = new byte[5] ;
//第一次读
int len = fis.read(bytes);
System.out.println(len);
//展示内容
System.out.println(new String(bytes,0,len));//从0开始,每次获取的实际长度
//第二次读
len = fis.read(bytes) ;
System.out.println(len);
System.out.println(new String(bytes,0,len));
//第三次度
len = fis.read(bytes) ;
System.out.println(len);
System.out.println(new String(bytes,0,len));
//第四次读
len = fis.read(bytes) ;
System.out.println(len);
System.out.println(new String(bytes,0,len));
//第五次读
len = fis.read(bytes) ;
System.out.println(len);
System.out.println(new String(bytes,0,len));*/
//返回结果是否为-1:作为读取完毕的结束条件
//优化 :byte[] bytes = new byte[5] ;定义的字节数组:缓冲区长度得多大?
//一般是1024(足够大)或者1024的整数倍
//最终版代码
byte[] bufferBytes = new byte[1024] ;
//实际字节数
int len = 0 ;
//赋值,判断,获取
while((len=fis.read(bufferBytes))!=-1){
//获取内容 :一定带上 0,实际字节数
System.out.println(new String(bufferBytes,0,len));
}
//释放资源
fis.close();
}
}
举例:
/*需求:
将当前项目下的FileOutputStreamDemo.java 复制到D:\JavaEE_2104\EE_day25\code Copy.java
分析:
源文件---->当前项目下的FileOutputStreamDemo.java
使用文件字节输入流:FileInputStream :一次读取一个字节/一次读取一个字节数组
当前输入流对象指向:FileOutputStreamDemo.java
目标文件--->D:\JavaEE_2104\EE_day25\code\Copy.java
使用文件字节输出流:FileOutputStream: 写一个字节/写一个字节数组,从0开始,写入实际长度
*/
public class CopyFileDemo {
public static void main(String[] args) throws Exception {
//创建一个文件字节输入流对象
FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java") ;
//创建一个文件字节输出流对象
FileOutputStream fos = new FileOutputStream("D:\\JavaEE_2104\\EE_day25\\code\\Copy.java") ;
long start = System.currentTimeMillis() ;
//读写复制操作
//方式1:一次读取一个字节
/* int by = 0 ;
while((by=fis.read())!=-1){
//读一个字节,写入一个字节
fos.write(by);
}*/
//方式2:一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=fis.read(bytes))!=-1){
//写入一个字节数组,并且从0开始,写入实际的字节数
fos.write(bytes,0,len);
}
long end = System.currentTimeMillis() ;
System.out.println("共耗时:"+(end-start)+"毫秒");
//关闭资源
fos.close();
fis.close();
}
}
举例:
/*将当前项目下的高圆圆.jpg复制到
D:\JavaEE_2104\EE_day25\code\mv.jpg
*/
public class CopyImage {
private static FileOutputStream fos = null ;
private static FileInputStream fis = null ;
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis() ;
// copy("高圆圆.jpg","D:\\JavaEE_2104\\EE_day25\\code\\mv.jpg") ;
copy2("高圆圆.jpg","D:\\JavaEE_2104\\EE_day25\\code\\mv.jpg") ;
close(fos,fis) ;
long end = System.currentTimeMillis() ;
System.out.println("共耗时"+(end-start)+"毫秒");
}
//一次读取一个字节数组
private static void copy2(String srcFile, String destFile) throws Exception {
//封装源文件--字节输入流对象
fis = new FileInputStream(srcFile) ;
//封装目的地文件
fos = new FileOutputStream(destFile) ;
//读写操作
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
close(fos,fis);
}
//一次读取一个字节
private static void copy(String srcFile, String destFile) throws Exception {
//封装源文件--字节输入流对象
fis = new FileInputStream(srcFile) ;
//封装目的地文件
fos = new FileOutputStream(destFile) ;
//读写操作
int by = 0 ;
while((by=fis.read())!=-1){
fos.write(by);
}
close(fos,fis);
}
//流资源关闭的功能
private static void close(FileOutputStream fos,FileInputStream fis) {
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
8). Java提供了比一次读取一个字节数组更高效的方式:缓冲流
BufferedOutputStream
BufferedOutputStream(OutputStream out) :指定默认的缓冲长度:足够大了
写
public void write(int b)
public void write(byte[] b,int off,int len)
BufferedInputStream
BufferedInputStream(InputStream in)
读
public int read()
public int read(byte[] bytes)
public int read(byte[] bytes,int offset,int len)
内部只是提供一个字节数组(缓冲区):长度8192个长度
构造方法都是默认的缓冲区大小,文件的操作还需要通过最底层的基本的字节流操作
缓冲流都是不直接操作文件,仅仅是提供内部缓冲区(提高读写效率!)
//错误的: BufferedOutputStream bos = new BufferedOutputStream("bos.txt") ;
举例:
public class BufferedStreamDemo {
public static void main(String[] args) throws Exception{
//创建一个字节缓冲输出流对象
//BufferedOutputStream(OutputStream out)
//内部提供的技术一个字节数组:byte[] buf = new byte[size]; //size:8192(默认缓冲区长度)
/* BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("bos.txt")) ;
bos.write("hello,BufferedOutputStream".getBytes());
//关闭流
bos.close();*/
//创建一个字节缓冲输入流对象:
// BufferedInputStream(InputStream in)
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream("FileOutputStreamDemo.java")) ;
//类名(抽象类 参数)---->装饰者设计模式
//1)当前类名
//2)形式参数:一般为当期类的父类(抽象的)
//3)还要提供抽象类的具体的子类
//一次读取一个字节
/* int by = 0 ;
while((by = bis.read())!=-1){
System.out.print((char)by);
}*/
//一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=bis.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
//关闭
bis.close();
}
}
举例:
/*将D盘下的冒泡.mp4视频文件复制到当前项目下的copy.mp4
*
* 使用基本的字节流一次读取一个字节数组
* 耗时247毫秒
*使用字节缓冲流一次读取一个字节数组
* 耗时78毫秒
*
*
* 针对一个文件读写复制几种方式?
* 基本的字节流:一次一个字节
* 基本的字节流:一次一个字节数组
*
* 字节缓冲流:一次一个字节
* 字节缓冲流:一次一个字节数组
*
*/
public class CopyMp4 {
public static void main(String[] args) throws Exception{
long start = System.currentTimeMillis() ;
// copyMp4("D:\\冒泡.mp4","copy.mp4") ;
copyMp4_2("D:\\冒泡.mp4","copy.mp4") ;
long end = System.currentTimeMillis() ;
System.out.println("耗时"+(end-start)+"毫秒");
}
//高效流:字节缓冲输入流一次读取一个字节数组
private static void copyMp4_2(String src, String dest) throws Exception {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(src)) ;
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest)) ;
//一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
//释放
bos.close();
bis.close();
}
//基本的字节流读写复制(一次读取一个字节数组)
private static void copyMp4(String src, String dest) throws Exception {
FileInputStream fis = new FileInputStream(src) ;
FileOutputStream fos = new FileOutputStream(dest) ;
//一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
//释放
fos.close();
fis.close();
}
}
9). 字符缓冲输入流和字符缓冲输出流:提供默认的缓冲区大小,读写的操作还需要交给底层字节流
为了针对文本文件操作,提高执行效率!
BufferedWriter
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
构造方法
BufferedWriter(Writer out)
成员方法:
public void newLine():换行功能
字符缓冲输入流:BufferedReader
构造方法:
public BufferedReader(Reader in)
特有功能:
public String readLine()
举例:
public class BufferedStreamDemo {
public static void main(String[] args)throws Exception {
/* //创建一个字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(
new FileWriter("bw.txt")) ;
for(int x = 0 ; x < 10 ; x ++){
bw.write("hello"+x);
// bw.write("\r\n");
//直接使用特有功能
bw.newLine();
bw.flush();
}
//关闭
bw.close();
*/
System.out.println("-------------------------------------------");
//使用字符缓冲输入流对象读取bw.txt
//创建一个字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("bw.txt")) ;
// public String readLine()
/* //第一次读
String line = br.readLine();
System.out.println(line);
//第二次读
line = br.readLine();
System.out.println(line);
//第三次读
line = br.readLine();
System.out.println(line);
//第四次读
line = br.readLine();
System.out.println(line);
//第五次读
line = br.readLine();
System.out.println(line); //空行
//第六次读
line = br.readLine();
System.out.println(line);*/
String line = null ;
while((line=br.readLine())!=null){
System.out.println(line);
}
//释放资源
br.close();
System.out.println("-------------------------------------------");
//读写复制操作:
//将当前项目下的OutputStreamWriterDemo.java复制D:\JavaEE_2104\EE_day25\code\\day25.java
//字符缓冲输入流
BufferedReader br2 = new BufferedReader(
new FileReader("OutputStreamWriterDemo.java")) ;
//字符缓冲输出流
BufferedWriter bw2 = new BufferedWriter(
new FileWriter("D:\\JavaEE_2104\\EE_day25\\code\\day25.java")) ;
String line2 = null ;
while((line2=br2.readLine())!=null){
bw2.write(line2);
bw2.newLine();
bw2.flush();
}
//关闭资源
bw2.close();
br2.close();
}
}
10). 字符输入
Reader(抽象类)
InputStreamReader 是字节流通向字符流的桥梁
构造方法:
public InputStreamReader(InputStream in):使用默认字符集进行解码(utf-8:跟idea的配置有关系)
public InputStreamReader(InputStream in,String charsetName):使用指定的字符集进行解码
在读写的时候,必须要保证编码和解码统一!
举例:
public class InputStreamReaderDemo {
public static void main(String[] args) throws Exception{
//创建字符输入流对象:使用字符转换输入流
/* InputStreamReader isr =
new InputStreamReader(new FileInputStream("osw.txt"),"gbk") ;*/
InputStreamReader isr =
new InputStreamReader(new FileInputStream("osw.txt"));
/* int by = isr.read();
System.out.println(by);*/
//一次读取一个字符
/* int by = 0 ; //字符数
while((by=isr.read())!=-1){
System.out.print((char)by); //字符数 (单个字符会ASCII码表的值)
}*/
//一次读取一个字符数组
char[] chs = new char[1024] ;
int len = 0 ;
while((len=isr.read(chs))!=-1){
System.out.println(new String(chs,0,len));
}
//释放
isr.close();
}
}
11). 字符流
字符输入
字符输出
Writer(抽象类)
子类:字符转换输出流:OutputStreamWriter 是字符流通向字节流的桥梁
构造方法:
OutputStreamWriter(OutputStream out) :创建转换输出流对象:平台默认编码集(utf-8)
OutputStreamWriter(OutputStream out,String charsetName):使用指定的字符集编码
举例:
public class OutputStreamWriterDemo {
public static void main(String[] args) throws Exception{
//创建一个字符输出流对象
// OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"),"utf-8") ;
OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("osw.txt")) ;
//字符流:
// 写的数据功能
/* void write(char[] cbuf)
写入字符数组。
abstract void write(char[] cbuf, int off, int len)
写入字符数组的某一部分。
void write(int c)
写入单个字符。
void write(String str)
写入字符串。
void write(String str, int off, int len)*/
osw.write("hello,字符流");
//关闭流的之前,刷新该流(将字符流的内存中底层保存的字节刷新)
osw.flush();
//关闭资源 --- 关闭系统资源指向文件的 线程!
osw.close(); //内存对象已经为null(流已经关闭)
// osw.flush();
// osw.write("hello,javaee");// java.io.IOException: Stream closed
}
}
12). 使用字符转换流将当前项目下的:CopyMp4.java复制到D:\EE_2104\EE_day25\code a.java
D:\JavaEE_2104\EE_day25\code\a.java
读写复制:
针对文本文件:.txt/java---- 都是直接使用字符流!
针对图片文件,视频文件,音频文件等等----都是直接使用字节流!
字符转换流的便捷类:只是为了书写简单
InputStreamReader---->FileReader(File file)/FileReader(String pathname) :平台默认的解码集(idea—utf-8)
OutputStreamWriter —>FileWriter(File file)/FileWriter(String pathname):默认的编码
举例:
public class CopyFile {
public static void main(String[] args) throws Exception{
//创建转换输入流对象 解码 平台默认编码集
/*InputStreamReader isr =
new InputStreamReader(new FileInputStream("CopyMp4.java")) ;
//字符转换输出流 :编码 平台默认编码集
OutputStreamWriter osw =
new OutputStreamWriter(new FileOutputStream("D:\\JavaEE_2104\\EE_day25\\code\\a.java"));*/
//针对文件操作的字符输入流
FileReader fr = new FileReader("CopyMp4.java") ;
//针对文件操作的字符输出流
FileWriter fw = new FileWriter("D:\\JavaEE_2104\\EE_day25\\code\\a.java");
//一次读取一个字符数组
char[] chs = new char[1024] ;
int len = 0 ;
while((len=fr.read(chs))!=-1){
//写
fw.write(chs,0,len);
//刷新
fw.flush() ;
}
//关闭
fw.close();
fr.close();
}
}
三、键盘录入的三种方式
键盘录入三种
1)main方法的参数(早期的)
2)jdk5以后提供的Scanner
3)BufferedReader(Reader r)
举例:
public class Test {
public static void main(String[] args) throws Exception{
//创建一个字符缓冲输入流对象
// Scanner sc = new Scanner(System.in) ;
InputStream in = System.in ;
//抽象类指向子类
Reader r = new InputStreamReader(in) ;
BufferedReader br = new BufferedReader(r) ;
//提示
System.out.println("请您输入一个int类型的内容:");
String line = br.readLine(); //阻塞式方法: 不录入内容,一直等待
int i = Integer.parseInt(line); //line:数字字符串
System.out.println("您输入的数据是:"+i);
}
}