IO
I: Input
O:Output
通过IO可以完成硬盘文件的读和写。
IO流的分类:
1、流的方向分类
(1)往内存中去读 - 输入;
(2)从内存中出来,写 - 输出。
2、另一种方式是按照读取数据方式不同进行分类
(1)按字节读取
有的流是按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位,这种流是万能的,什么类型的文件都可以读取,包括:文本文件、图片、声音文件、视频文件等等··· ···
(2)按字符读取
有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取普通文本文件而存在的,他不能读取:图片、声音、视频等文件。只能读取纯文本文件,连word文件都读取不了。
IO四大家族
java.io.InputStream 字节输入流
java.io.OutputStream 字节输出流
java.io.Reader 字符输入流
java.ioWriter 字符输出流
注意:在java中只要 "类名" 以stream 结尾 的都是字节流。以 "Reader/Writer" 结尾的都是字符流。
所有流都实现了 java.io.Closeable接口,都是可以关闭的,都有close() 方法。
流毕竟是一个管道,是内存和硬盘之间的通道,用完之后一定要关闭,不然会耗费(占用)很多资源。
所有流都实现了java.io.Flushable接口,都是可刷新的,都有flush() 方法。
输出流在最终输出之后,一定要记得flush(),刷新一下,这个刷新表示将通道、管道当中剩余的为输出的数据强行输出完毕(清空管道),刷新的作用就是清空管道。
注意:如果没有flush() 可能会丢失数据。
几个常用的流:
// 文件专属
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
// 转换流(将字节流转化为字符流)
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
// 缓冲流专属:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
// 数据专属流:
import java.io.DataInputStream;
import java.io.DataOutputStream;
// 标准输出流
import java.io.PrintStream;
import java.io.PrintWriter;
// 对象专属
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
以FileInputStream为例
从硬盘到内存(例:上传图片)
1、new FileInputStream(path) 创建流
public class IOStream {
public static void main(String[] args) {
String imagePath = null;
FileInputStream fileInputStream = null;
try {
// 获取图片路径
imagePath = ResourceUtils.getURL("classpath:").getPath()+"static/image/0710.jpg";
System.out.println("imagePath: "+imagePath);
// 创建一个流()
fileInputStream = new FileInputStream(imagePath);
System.out.println("fileInputStream: "+fileInputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
// 确保流的存在,在关闭它,否则报:空指针异常
if(fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2、fileInputStream.read() 读取流
读取流,一次读一个字节,读到最后如果没读到数据会返回-1。
注意:一次读取一个字节,效率很低。
public class IOStream {
public static void main(String[] args) {
// 获取图片路径
String imagePath = ResourceUtils.getURL("classpath:").getPath()+"static/image/0710.jpg";
System.out.println("imagePath: "+imagePath);
// 创建一个流()
FileInputStream fileInputStream = new FileInputStream(imagePath);
while(fileInputStream.read() != -1) {
System.out.println(fileInputStream.read());
}
}
}
3、(重点)Int byteCount = fileInputStream.read( Byte[ ] byte )
往byte数组中读,一次读取 byte.length个字节。减少磁盘与内存之间的交互,提高程序的执行效率
返回值是:每次读到的字节数量,最后读取不到返回-1。
public class IOStream {
public static void main(String[] args) {
String imagePath = null;
FileInputStream fileInputStream = null;
try {
// 获取路径
imagePath = ResourceUtils.getURL("classpath:").getPath()+"static/image/0710.jpg";
System.out.println("imagePath: "+imagePath);
// 创建一个流()
fileInputStream = new FileInputStream(imagePath);
// 创建一个长度为100 的字节数组,每次会往字节数组中放入 10个字节的图片数据。
byte[] byteArray = new byte[100];
// 返回的是每一次读到的字节数量
int byteCount = 0;
while((byteCount = fileInputStream.read(byteArray)) != -1) {
// 把字节数组转化为字符串,参数二:开始转化的字节索引位,参数三:要解码的字节数
System.out.println(new String(byteArray, 0, byteCount));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 确保流的存在,在关闭它,否则报:空指针异常
if(fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
4、fileInputStream.available( )
获取剩余未读到的字节数量,可以利用这个方法计算要读的资源的字节大小n,然后创建 一个 n大小的字节数组,这样就不需要要循环来读取了。
注意:这种方式不适合大文件,因为byte数组不能太大,且 fileInputStream.available( ) 返回的是int类型的!
public class IOStream {
public static void main(String[] args) {
String imagePath = null;
FileInputStream fileInputStream = null;
try {
// 获取路径
imagePath = ResourceUtils.getURL("classpath:").getPath()+"static/test.txt";
fileInputStream = new FileInputStream(imagePath);
// 获取未读到的字节数量
int unreadByteCount = fileInputStream.available();
// 创建一个字节数组,大小就是资源的字节大小,这样就不需要每次循环读取了
byte[] bytes = new byte[unreadByteCount];
fileInputStream.read(bytes);
String byteString = new String(bytes);
System.out.println(byteString);
} catch (IOException e) {
e.printStackTrace();
} finally {
// 确保流的存在,在关闭它,否则报:空指针异常
if(fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
小例子:
获取图片base64编码:
// 获取图片base64
// param-> imageFile 图片真实的路径 (例:c:\d\1.jpg)
private static byte[] getbase64Url(String imageFile) {
InputStream inputStream = null;
byte[] data = null;
try {
// 转输入流
inputStream = new FileInputStream(imageFile);
// 定义字节数组大小 inputStream.available()获取流大小
data = new byte[inputStream.available()];
// 图片流读到数组中去,从磁盘向内存中读
inputStream.read(data);
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return data;
}
以FileOutputStream为例
从内存到硬盘。
1、new FileInputStream(path) 创建写入流(文件不存在:会创建一个文件,存在:会先清空源文件内容,然后在重新写入内容)
文件不存在,创建新文件:
向static文件夹下写入1.txt
public class IOStream {
public static void main(String[] args) {
FileOutputStream fileOutputStream = null;
try {
String filePath = ResourceUtils.getURL("classpath:").getPath()+"static/1.txt";
fileOutputStream = new FileOutputStream(filePath);
// 开始写。
byte[] bytes = {97, 98, 99, 120};
fileOutputStream.write(bytes);
// 写入后要刷新
fileOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(fileOutputStream != null) {
fileOutputStream.close()
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
注意:如果一个文件夹中没有任何文件(空文件夹),打包时会过滤掉,不会打包!所以写入的时候,不能写入一个空文件夹,否则会报:文件找不到!
2、源文件存在,在文件末尾写入内容
String filePath = ResourceUtils.getURL("classpath:").getPath()+"static/1.txt";
fileOutputStream = new FileOutputStream(filePath, true);
3、把字符串写入文件
public class fileStream {
public static void main(String[] args) {
FileOutputStream fileOutputStream = null;
try {
String filePath = ResourceUtils.getURL("classpath:").getPath()+"static/1.txt";
fileOutputStream = new FileOutputStream(filePath, true);
// 把字符串写入文件。
String say = "大家好,我来自火星!";
// 字符串转byte数组
byte[] bytes = say.getBytes();
// 开始写。
fileOutputStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(fileOutputStream != null) {
// 输出后要刷新
fileOutputStream.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4、小例子:拷贝一个文件
// 文件复制 - 把指定文件复制到指定目录下文件。
public class fileStream {
public static void main(String[] args) {
FileOutputStream outStream = null;
FileInputStream inputStream = null;
try {
// 指定一个复制的目录文件
String path = ResourceUtils.getURL("classpath:").getPath()+"static/2.jpg";
inputStream = new FileInputStream("C:\\Users\\l'x'c\\Desktop\\1.jpg");
outStream = new FileOutputStream(path);
//边读边写
byte[] bytes = new byte[10 * 1024]; // 每次读10kb
int byteCount = 0;
while((byteCount = inputStream.read(bytes)) != -1) {
// 写入指定数量
outStream.write(bytes, 0, byteCount);
}
outStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(outStream != null) {
try {
outStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
PrintStream
标准输出流,使用这个流我们可以把原本输出到控制台中的信息,输出到文件中。
// 文件复制 - 把指定文件复制到指定目录下文件。
public class fileStream {
public static void main(String[] args) {
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
String fileName = simpleDateFormat.format(date);
String dest = null;
try {
dest = ResourceUtils.getURL("classpath:").getPath()+"static/"+simpleDateFormat.format(date)+".log";
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
FileOutputStream fileStream = new FileOutputStream(dest, true);
//标准输出流 PrintStream参数是一个 OutputStream,我们可以用 FileOutputStream,
// 因为 FileOutputStream继承OutputStream
// 创建一个标准输出流,输出到static文件夹下的 log文件中。
PrintStream printStream = new PrintStream(fileStream);
// 改变输出流的方向
System.setOut(printStream);
// 输出的信息
printStream.println(fileName+":大家好,我来自火星!");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
对象专属流
待记录。