流是对字节序列的抽象,我们可以将其想象成一个水流,区别就是流的不是水而是字节。
一、分类
1、输入流/输出流
水流是有方向的,java中的流也是有方向的,分为输入流、输出流。这个输入输出是相对的,都是以程序的角度来看的。从程序将数据写入文件叫做输出流,将数据从文件读入程序叫做输入流。
2、字符流/字节流
字节流处理字节的最小单位是单个字节,通常用来处理二进制数据,比如图片文件、音频文件等。最基本的字节流输入流是InputStream, 最基本的字节流输出流是OutputStream。
字符流处理字节的最小单位是Unicode码元,占两个字节,通常用来处理文本数据。它存在的意义是比如像汉字,占着两个字节,如果使用字节流一个字节一个字节读取的话读的都是半个字,无法显示。最基本的字符流输入流是Reader,最基本的字符输出流是Writer。

3、节点流/处理流
节点流可以从特定的数据源读取数据(节点可以是文件、内存)。
处理流是在节点流或处理流的基础上,通过数据处理能够提供更加强大的数据存取功能。


二、字节流
1、InputStream
InputStream:字节输入流基类,抽象类是表示字节输入流的所有类的超类 。
常用方法:
abstract int read() // 从输入流中读取数据的下一个字节
int read(byte[] b) // 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b中
int read(byte[] b, int off, int len) // 将输入流中最多 len 个数据字节读入 byte 数组
long skip(long n) // 跳过和丢弃此输入流中数据的 n个字节
void close() // 关闭此输入流并释放与该流关联的所有系统资源
2、OutputStream
OutputStream:字节输出流基类,抽象类是表示输出字节流的所有类的超类。
常用方法:
void write(byte[] b) // 将 b.length 个字节从指定的 byte 数组写入此输出流
void write(byte[] b, int off, int len) // 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流
abstract void write(int b) // 将指定的字节写入此输出流
void close() // 关闭此输出流并释放与此流有关的所有系统资源
void flush() // 刷新此输出流并强制写出所有缓冲的输出字节
3、FileInputStream
FileInputStream:字节文件输入流,从文件系统中的某个文件中获得输入字节,用于读取诸如图像数据之类的原始字节流,继承自InputStream。
构造方法:
FileInputStream(File file)
FileInputStream(String name)
4、FileOutputStream
FileOutputStream:字节文件输出流是用于将数据写入到File,从程序中写入到其他位置。
FileOutputStream(File file)
FileOutputStream(File file, boolean append) //append代表是否追加
FileOutputStream(String name)
FileOutputStream(String name, boolean append)
package file;
import java.io.*;
public class FileInputStreamTest {
public static void main(String[] args) {
try {
//这个可以打印 Hello,world
FileInputStream fileInputStream = new FileInputStream("D://a.txt");
int ch = fileInputStream.read();
while(-1 != ch){
System.out.print((char) ch);
ch = fileInputStream.read();
}
/**********************************/
//这个没有打印,因为fileInputStream中的东西已经被读完了
byte[] buffer = new byte[8];
fileInputStream.read(buffer);
for(int i = 0; i < buffer.length; i++){
System.out.print((char)buffer[i]);
}
/**********************************/
//这个打印了 Hello,wo 刚好是八个字符,先把输入流中的东西读入缓存字节数组中,然后再读
FileInputStream fileInputStream1 = new FileInputStream("D://a.txt");
byte[] buffer1 = new byte[8];
fileInputStream1.read(buffer1);
System.out.println();
for(int i = 0; i < buffer1.length; i++){
System.out.print((char) buffer1[i]);
}
/**********************************/
//在D盘下创建了一个b.txt, 内容是 wangxban ,首先写了一个wangxb,然后再在后面加一个an
FileOutputStream fileOutputStream = new FileOutputStream("D://b.txt");
byte[] buffer2 = {'w','a','n','g','x','b'};
fileOutputStream.write(buffer2);
fileOutputStream.write(buffer2, 1,2);
/**********************************/
//在D盘下创建一个b文件夹,然后在b文件夹中创建一个b.txt
//直接这样写会报错,因为没有b这个文件夹
/*FileOutputStream fileOutputStream1 = new FileOutputStream("D:\\b\\b.txt");
fileOutputStream1.write(buffer2);*/
//先创建一个b文件夹,然后再往里面写
File file = new File("D://b");
if(!file.exists()){
file.mkdir();
}
FileOutputStream fileOutputStream1 = new FileOutputStream("D://b//b.txt");
fileOutputStream1.write(buffer2);
fileInputStream.close();
fileInputStream1.close();
fileOutputStream.close();
fileOutputStream1.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

控制台执行结果:

5、BufferedInputStream
BufferedInputStream:字节缓冲输入流,提高了读取效率。缓冲区(Buffer)就是内存里面的一小块区域,读写数据时都是先把数据放到这块缓冲区域里面,减少io对硬盘的访问次数。缓冲区就像水桶,把数据想象成水,把要处理的数据先放入水桶,装满后再做处理。先把数据放置到缓冲区上,等到缓冲区满了以后,再一次把缓冲区里面的数据写入到硬盘上或者读取出来,这样可以有效地减少对硬盘的访问次数。
构造方法:
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in, int size)
package file;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class BufferStreamDemo {
public static void main(String[] args) {
try {
//读取
FileInputStream fileInputStream = new FileInputStream("D://b.txt");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
int a = bufferedInputStream.read();
while(-1 != a){
System.out.print((char) a);
a = bufferedInputStream.read();
}
/***************************************/
//写入
FileOutputStream fileOutputStream = new FileOutputStream("D://c.txt");
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
byte[] bytes = {'w','a','n','g','x','b','w','a','n','g','x','b','w','a','n','g','x','b','w','a','n','g','x','b','w','a','n','g','x','b',
'w','a','n','g','x','b','w','a','n','g','x','b','w','a','n','g','x','b','w','a','n','g','x','b','w','a','n','g','x','b','w','a','n','g','x','b'};
bufferedOutputStream.write(bytes);
//flush的作用是将清空缓存区的数据,如果不flush,不会将内容写入文件
//一定要写flush,并且flush要写在close之前,不然会导致java.io.IOException: Stream Closed
bufferedOutputStream.flush();
fileOutputStream.close();
bufferedOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
三、字符流
1.Reader
Reader:读取字符流的抽象类.
常用方法:
int read() // 读取单个字符
int read(char[] cbuf) // 将字符读入数组
abstract int read(char[] cbuf, int off, int len) // 将字符读入数组的某一部分
long skip(long n) // 跳过字符
abstract void close() // 关闭该流并释放与之关联的所有资源
2.Writer
Writer:写入字符流的抽象类.
常用方法:
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) // 写入字符串的某一部分
Writer append(char c) // 将指定字符添加到此 writer
Writer append(CharSequence csq) // 将指定字符序列添加到此 writer
Writer append(CharSequence csq, int start, int end) // 将指定字符序列的子序列添加
abstract void close() // 关闭此流,但要先刷新它
abstract void flush() // 刷新该流的缓冲
package file;
import java.io.*;
public class BufferedReaderWriterDemo {
/*mkdirs()可以建立多级文件夹, mkdir()只会建立一级的文件夹, 如下:
new File("/tmp/one/two/three").mkdirs();
执行后, 会建立tmp/one/two/three四级目录
new File("/tmp/one/two/three").mkdir();
则不会建立任何目录, 因为找不到/tmp/one/two目录, 结果返回false*/
public static void main(String[] args) {
try {
FileReader fileReader = new FileReader("D://test1.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
File file = new File("D://test1");
if(!file.exists()){
file.mkdir();
}
FileWriter fileWriter = new FileWriter("D://test1/test1.txt");
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
String str = bufferedReader.readLine();
while(str != null){
bufferedWriter.write(str);
bufferedWriter.newLine();
str = bufferedReader.readLine();
}
bufferedWriter.flush();
fileReader.close();
bufferedReader.close();
fileWriter.close();
bufferedWriter.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
四、字节缓冲流
ByteArrayOutputStream/ByteArrayInputStream
package file;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ByteArrayStreamDemo {
//ByteArrayOutputStream在创建实例时,内部创建一个byte型的数组缓冲区,
//然后利用ByteArrayOutputStream和ByteArrayInputStream的实例向数组中写
//入或读出byte型数据。在网络传输中我们往往要传输很多变量,我们可以利用
//ByteArrayOutputStream把所有的变量收集到一起,然后一次性把数据发送出去。
public static void main(String[] args) {
try {
FileInputStream fileInputStream = new FileInputStream("D://a.txt");
//在创建ByteArrayOutputStream类实例时,内存中会创建一个byte数组类型的缓冲区,
//缓冲区会随着数据的不断写入而自动增长
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
//将内容读入到buffer中
while((len = fileInputStream.read(buffer)) != -1){
//将每次督导字节数组中的内容写入内存缓冲区
byteArrayOutputStream.write(buffer, 0 , len);
}
//可使用toByteArray()和toString()获取数据
byte[] data = byteArrayOutputStream.toByteArray();
//关闭ByteArrayOutputStream无效,此类中的方法在关闭此流后仍可被调用,
//而不会产生任何IOException
fileInputStream.close();
String result = new String(data, "UTF-8");
System.out.println(result);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
五、数据流
DataOutputStream/DataInputStream
package file;
import java.io.*;
public class DataStreamDemo {
//来读取和写各种类型的数据,如字符串、boolean、double、float
//FileOutPutStream也能写,但只能写int、byte
//一定要注意 DataOutputStream 与DataInputStream配合使用,而且二者读写的顺序要一样
public static void main(String[] args) {
//定义字节数组流
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
dataOutputStream.writeUTF("Hello"); //字符串
dataOutputStream.writeChar('C'); //单个字符
dataOutputStream.writeBoolean(true);
dataOutputStream.writeDouble(3D);
dataOutputStream.writeFloat(3F);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
//返回从这个输入流中读取余下的字节数
System.out.println(byteArrayInputStream.available());
DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream);
System.out.println(dataInputStream.readUTF());
System.out.println(dataInputStream.readChar());
System.out.println(dataInputStream.readBoolean());
System.out.println(dataInputStream.readDouble());
System.out.println(dataInputStream.readFloat());
dataOutputStream.close();
dataInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

六、打印流
PrintStream/PrintWriter
package file;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
public class PrintStreamDemo {
public static void main(String[] args) {
testPrintStream();
//testPrintWriter();
}
public static void testPrintStream(){
PrintStream printStream = null;
try {
FileOutputStream fileOutputStream = new FileOutputStream("D://e.txt");
printStream = new PrintStream(fileOutputStream);
if(printStream != null){
System.setOut(printStream);
}
for(int c = 0; c <= 60; c++){
//上面设置了输出到打印流中,控制台不打印
System.out.print(c + ",");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static void testPrintWriter(){
String s = null;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
try {
FileWriter fileWriter = new FileWriter("D://f.txt");
PrintWriter printWriter = new PrintWriter(fileWriter);
while((s = bufferedReader.readLine()) != null){
if(s.equalsIgnoreCase("exit")){
break;
}
System.out.println(s.toUpperCase());
printWriter.println(s.toUpperCase());
}
printWriter.println("*************" + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));
printWriter.flush();
printWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
七、对象流
ObjectOutputStream/ObjectInputStream
package file;
import java.io.*;
public class ObjectStreamDemo {
public static void main(String[] args) {
User user = new User();
user.age = 12;
user.name = "wade";
user.name = "911";
try {
FileOutputStream fileOutputStream = new FileOutputStream("D://g.txt");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(user);
objectOutputStream.flush();
objectOutputStream.close();
FileInputStream fileInputStream = new FileInputStream("D://g.txt");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
User user1 = (User) objectInputStream.readObject();
System.out.println(user1.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
static class User implements Serializable{
private int age;
private String name;
//transient透明的,用来修饰的变量在序列化时不予考虑,当其不存在
private transient String phone;
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
", phone='" + phone + '\'' +
'}';
}
}
}

八、文件操作
1、删除文件或文件夹
package file;
import java.io.File;
public class FileDemo1 {
public static boolean deleteFilesOrDir(String fileName){
File file = new File(fileName);
if(!file.exists()){
System.out.println("文件删除失败," + fileName + "不存在");
return false;
}else{
if(file.isFile()){
return FileDemo1.deleteFiles(fileName);
}else{
return FileDemo1.deleteDir(fileName);
}
}
}
public static boolean deleteFiles(String fileName){
File file = new File(fileName);
if(file.exists() && file.isFile()){
if(file.delete()){
System.out.println("文件删除成功");
return true;
}else{
System.out.println("文件删除失败");
return false;
}
}else{
System.out.println("文件删除失败," + fileName + " 不存在");
return false;
}
}
public static boolean deleteDir(String dir){
if(!dir.endsWith(File.separator)){
dir += File.separator;
}
File dirFile = new File(dir);
if(!dirFile.exists() || !dirFile.isDirectory()){
System.out.println("文件夹删除失败 !" + dir + " 不存在");
return false;
}
boolean flag = true;
File[] files = dirFile.listFiles();
for(int i = 0; i < files.length; i++){
if(files[i].isFile()){
flag = FileDemo1.deleteFiles(files[i].getAbsolutePath());
if(!flag){
break;
}
}else if(files[i].isDirectory()){
flag = FileDemo1.deleteDir(files[i].getAbsolutePath());
if(!flag){
break;
}
}
}
if(!flag){
System.out.println("删除文件夹失败");
}
if(dirFile.delete()){
System.out.println("文件夹" + dir + "删除成功!");
return true;
}else{
return false;
}
}
}
2、移动文件或文件夹
package file;
import java.io.File;
public class FileDemo2 {
public static void main(String[] args) {
// System.out.println("调用移动文件");
// String sourceFileName = "D://b//bbb.txt";
// String targetFileName = "D://test2//bbb.txt";
// FileDemo2.moveFile(sourceFileName, targetFileName);
System.out.println("调用移动目录");
String sourceDir = "D://b//b";
String targetDir = "D://test1";
FileDemo2.moveDir(sourceDir, targetDir, true);
}
public static boolean moveFile(String sourceFileName, String targetFileName){
return FileDemo2.moveFile(sourceFileName, targetFileName, true);
}
public static boolean moveDir(String sourceDirName, String targetFileName){
return FileDemo2.moveDir(sourceDirName, targetFileName, false);
}
public static boolean moveFile(String sourceFileName, String targetFileName, boolean isOverlay){
File sourceFile = new File(sourceFileName);
if(!sourceFile.exists()){
System.out.println("文件" + sourceFileName + "不存在,移动失败");
return false;
}else if(!sourceFile.isFile()){
System.out.println(sourceFileName + "不是文件,移动失败");
return false;
}
File targetFile = new File(targetFileName);
if(targetFile.exists()){
if(isOverlay){
System.out.println("目标文件已存在,准备删除它");
if(!FileDemo1.deleteFilesOrDir(targetFileName)){
System.out.println("文件移动失败,文件" + targetFileName + "删除失败");
return false;
}
}else{
System.out.println("文件移动失败,文件" + targetFileName + "已存在");
return false;
}
}else{
if(!targetFile.getParentFile().exists()){
System.out.println("文件" + targetFile + "所在目录不存在,正在创建");
if(!targetFile.getParentFile().mkdirs()){
System.out.println("移动文件失败,创建文件所在的文件夹失败");
return false;
}
}
}
if(sourceFile.renameTo(targetFile)){
System.out.println("移动源文件" + sourceFileName + "到" + targetFileName + "成功");
return true;
}else{
System.out.println("移动源文件" + sourceFileName + "到" + targetFileName + "失败");
return false;
}
}
public static boolean moveDir(String sourceDirName, String targetDirName, boolean isOverlay){
File sourceDir = new File(sourceDirName);
if(!sourceDir.exists()){
System.out.println("源目录" + sourceDirName + "不存在,移动目录失败");
return false;
}else if(!sourceDir.isDirectory()){
System.out.println("移动目录失败," + sourceDirName + "不是目录");
return false;
}
//如果目标文件名不是以文件分隔符结尾,自动添加文件分隔符
if(!targetDirName.endsWith(File.separator)){
targetDirName += File.separator;
}
File targetDir = new File(targetDirName);
if(targetDir.exists()){
if(isOverlay){
System.out.println("该目录已存在,准备删除它");
if(!FileDemo1.deleteFilesOrDir(targetDirName)){
System.out.println("移动目录失败,因目标目录已存在,删除目录" + targetDirName + "失败");
return false;
}
}else{
System.out.println("移动目录失败," + targetDirName + "已存在!");
return false;
}
}else{
System.out.println("该目录不存在,正在创建");
if(!targetDir.mkdirs()){
System.out.println("移动目录失败,创建目标目录失败");
return false;
}
}
boolean flag = true;
File[] files = sourceDir.listFiles();
for(int i = 0; i < files.length; i++){
if(files[i].isFile()){
flag = FileDemo2.moveFile(files[i].getAbsolutePath(),
targetDirName + files[i].getName(), isOverlay);
if(!flag){
break;
}
}else if(files[i].isDirectory()){
flag = FileDemo2.moveDir(files[i].getAbsolutePath(),
targetDirName + files[i].getName(), isOverlay);
if(!flag){
break;
}
}
}
if(!flag){
System.out.println("目录" + sourceDirName + "移动到" + targetDirName + "失败");
return false;
}
//删除原目录
if(FileDemo1.deleteDir(sourceDirName)){
System.out.println("目录" + sourceDirName + "移动到" + targetDirName + "成功");
return true;
}else{
System.out.println("目录" + sourceDirName + "移动到" + targetDirName + "失败");
return false;
}
}
}
网友评论