JAVA基础之IO流
一.概念
IO流:传输数据的一套机制
I:input (输入)
O:output(输出)
存储数据:内存 持久化存储
持久化存储:长期保存
IO流分为输入流和输出流
IO流从功能上来说分为字符流和字节流
字符流是只能操作字符(txt、.java、.html)
字节流:可以操作所有文件
输入流 | 输出流 | |
---|---|---|
字符流 | Reader | Writer |
字节流 | InputStream | OutputStream |
以上4种都是抽象类,不能直接使用
输入还是输出是相对于内存来说
如果向内存中读取内容,就是输入到内存。输入流
如果从内存中向外面写入内容,就是输出。
字符输出流:FileWriter 将字符写入到文件中
如果想要追加数据,在构造方法后面提供 true
二.字符输出流
1.字符输出流
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
public static void main(String[] args) throws IOException {
// 字符输出流
// 如果路径有,就直接创建文件
// 如果文件已经存在,会创建新的文件覆盖掉原来的文件
FileWriter fw = new FileWriter("F:\\a.txt",true);//往a.txt中添加,不覆盖
// 写入数据到缓冲区
fw.write("愿微风不燥,阳光正好,时光不老~");
// 冲刷缓冲区
// fw.flush();
// 关闭,释放资源
// 关闭时会自动冲刷缓冲区
fw.close();
// 清空对象
fw = null;
}
}
2.处理异常
异常处理:
1、先在try…catch外面声明对象,设置为null,保证对象的作用域在try…catch…finally里面
2、创建对象,并且在finally里面判断是否为null。因为一旦对象为null,那么就会出现空指针异常。
3、在finally的判断方法中,关闭流。关闭流也需要捕获异常,因为关闭流也不一定成功。
4、在捕获关闭流异常的try catch中添加finally,无论关闭流是否成功,都给对象设置为null。
5、如果写入数据,需要去冲刷缓冲区,防止数据的丢失。
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterExceptioonTest {
public static void main(String[] args) {
// 创建对象
FileWriter fw = null;
try {
fw = new FileWriter("F:\\b.txt");
fw.write("你好,hello world");
// 冲刷
fw.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (fw != null){
try {
fw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
fw = null;
}
}
}
}
}
3.JDK1.7的特性
Try with resource
try(AutoCloseable的子类/子接口){
对象可以保证自动关闭
}
注意:try小括号中内容不能是传递过来的
import java.io.FileWriter;
public class TryWithResourceDemo {
public static void main(String[] args) {
// JDK1.7特性
// try ... with ... resouce 可以保证自动关闭
// 使用格式 try(AutoCloseable的子类或者子接口)
// 可以保证里面的对象自动关闭
try (FileWriter fw = new FileWriter("F:\\b.txt")){ //注意小括号
fw.write("再见,周杰伦");
}catch(Exception e){
e.printStackTrace();
}
}
}
三.字符输入流:FileReader
FileReader默认一次读取一个字符,效率比较低下,可以通过字符数组形成一个缓冲区,从而来提升效率。
1.将文件内容读取到内存中 字符输入流
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo {
public static void main(String[] args) throws IOException {
// 将文件内容读取到内存中 字符输入流
// 创建对象
FileReader fr = new FileReader("F:\\c.txt");
// 读取字符
// 一次读取一个字符
// 如果读取到最后,没有字符,返回-1
// 因为是从文件中一个个的读取,所以这种写法,效率比较低
int ch;
while ((ch = fr.read()) != -1){
// 读一次打印一次
System.out.println((char)ch);
}
// 关闭流
fr.close();
}
}
2.通过字符数组作为缓冲区,读取数
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo02 {
public static void main(String[] args) throws IOException {
// 通过字符数组作为缓冲区,读取数据
FileReader fr = new FileReader("F:\\c.txt");
// 定义一个字符数组
char[] chs = new char[3];
// 读一次就获取对应字符数组长度的内容
// 如果没有读取到数据,那么返回-1
// 读取到的字符长度
int len;
while((len = fr.read(chs)) != -1){
System.out.println(new String(chs,0,len));
}
fr.close();
}
}
3.复制文件
import java.io.FileReader;
import java.io.FileWriter;
public class CopyTxt {
public static void main(String[] args) {
// 拷贝文件 思路:先去对应的文件中读取内容
// 读取一行写入一行
// 读取时候使用字符数组
long startTime = System.currentTimeMillis();
FileReader fr = null;
FileWriter fw = null;
try{
fr = new FileReader("F:\\a.txt");
fw = new FileWriter("F:\\b.txt");
// 先读再写
// 读取需要使用到字符数组,那么先创建数组
char[] chs = new char[1024 * 8];
// 定义一个变量来接收实际读取到的长度
int len;
while ((len = fr.read(chs)) != -1){
// 表示读取到了内容 长度就是len
// 写入到文件中
// fw.write(new String(chs,0,len));
fw.write(chs, 0, len);
}
fw.flush();
}catch(Exception e){
e.printStackTrace();
}finally{
// fr和fw都有可能是null
if (fr != null){
try{
fr.close();
}catch(Exception e){
e.printStackTrace();
}finally{
fr = null;
}
}
if (fw != null){
try{
fw.close();
}catch(Exception e){
e.printStackTrace();
}finally{
fw = null;
}
}
}
// 复制文本花费的总时间
System.out.println(System.currentTimeMillis() - startTime);
}
}
四.BufferedReader和BufferedReader
BufferedReader:默认提供了一个缓冲区,相对于fileReader效率更高。底层还是使用的FileReader来读取.
BufferedReader:提供一个特有的方法 readLine 可以一次读取一行字符串
注意:readLine并没有读取换行符 \r\n
设计模式:解决同一类问题的常用手段。
装饰设计模式:用同类的对象来构建本类对象,从而对所构建的本类对象的功能进行增强或者修复。
BufferedReader和BufferedWriter就是所谓的装饰设计模式
1.BufferedReader
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
// 创建对象
// 传入FileReader对象
// 底层使用FileReader
BufferedReader br = new BufferedReader(new FileReader("F:\\667.txt"));
// 可以一次读取一行
String str;
while((str = br.readLine()) != null){
System.out.println(str);
}
// 关闭流
br.close();
}
}
2.BufferedWriter
BufferedWriter:写入数据。提供了一个特有的方法(newLine),可以换行。
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedWriterDemo {
public static void main(String[] args) throws IOException {
// 创建对象
BufferedWriter bw = new BufferedWriter(new FileWriter("F:\\a689.txt"));
bw.write("爱情这杯酒,谁喝都会醉");
// 换行
bw.newLine();
bw.write("什么爱情,什么永久!!");
// bw.flush();
bw.close();
}
}
3.统计java代码行数
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class PracticeDemo {
static int javaCount = 0;
public static void main(String[] args) throws IOException {
// 统一workspace中的代码行数
// 代码都写在.java文件中
// 先找到.java文件
// 然后通过BufferedReader读取一行
// 然后进行行数的计数
// File类来操作文件和目录
File file = new File("F:\\workspace");
count(file);
System.out.println("总共写了" + javaCount + "行代码");
}
// 定义一个方法,来寻找.java文件
public static void count(File file) throws IOException{
if (file.isDirectory()){
// 如果是目录,列出目录所有内容
File[] files = file.listFiles();
for (File f : files) {
count(f);
}
}else if(file.getName().endsWith(".java")){
// 找到.java文件 CopyTxt.java
BufferedReader br = new BufferedReader(new FileReader(file.getAbsolutePath()));
String str;
while ((str = br.readLine()) != null){
javaCount++;
}
br.close();
}
}
}
五.FileInputStream和OutputStreamWriter
1.FileInputStream
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamDemo {
public static void main(String[] args) throws IOException {
// 字节输入流 以字节的形式输入到内存中
FileInputStream fis = new FileInputStream("F:\\c.txt");
// 定义字节数组,用于缓冲区
byte[] bys = new byte[10];
int len;
while ((len = fis.read(bys)) != -1){
System.out.println(new String(bys,0,len));
}
fis.close();
}
}
2.OutputStreamWriter
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class OutPutStreamDemo {
public static void main(String[] args) throws IOException {
// 转换输出流 可以将字节流转换为字符流
// 可以通过写入字符的形式来使用字节流
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("F:\\d.txt"));
// 写入数据
osw.write("4555645dfgdf");
// 关流
osw.close();
}
}
3.使用字节流拷贝文件
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyJPG {
public static void main(String[] args) throws IOException {
// 创建字节输入和输出流
FileInputStream fis = new FileInputStream("F:\\a.jpg");
FileOutputStream fos = new FileOutputStream("F:\\b.jpg");
// 读取图片
// 定义一个字节数组,用于缓冲区
byte[] bys = new byte[10];
// 读取的实际长度
int len;
while((len = fis.read(bys)) != -1){
// 代码执行到这里,代表读取成功
// 写入数据
fos.write(bys, 0, len);
}
// 关流
fos.close();
fis.close();
}
}
六.系统流
System.in | 标准输入流 |
---|---|
System.out | 标准输出流 |
System.err | 标准错误流 |
标准输出流和标准错误流可能出现高并发的问题。有可能位置不同,有可能不换行.
为什么没有关过Scanner???
Scanner里面使用System.in系统输入流,系统输入流是共享的。程序中只有一个系统输入流。当关闭Scanner时,会将Scanner中的参数系统输入流也关闭掉。就会导致整个程序不能再继续使用系统输入流。
以后见到系统流,不要关闭。
系统流都是字节流。