(以下内容为听网课学习的总结见解,若有bug还请包涵指教,)
IO流说白了就是像在搬家,从老家(源头)搬到新家(目的地),当然你绝对不会把整栋房子地基平移过去,你会叫搬家公司或者自个把家具等重要的东西一点点运到新家,就相当于数据被当成无结构的字节或字符序列,以流的形式传递,进行输入输出…
注(*代表星级)
流的意思:流动,从一端移动到另一端,源头与目的地
程序与文件|数组|网络连接|数据库,以程序为中心
流的方向:
输入流inputStream Reader
输出流outputSream writer
处理数据单元(节点流):
字节流:二进制,可以一切文件包括纯文本doc音频视频等
字符流:文本文件,只能处理纯文本
功能不同:
节点流:可以直接从数据源或目的地读写数据
处理流:不直接连接到数据源或目的地,是处理流的流,通过对其他的处理提高程序的性能 ,就相当于对节点流的修饰。
File(String pathname)这个pathname就是指路径 也是最常用的
例如:`File src = new File(“D:/1.txt”);
File (String parent,String child)这就相当于把上面那个肢解了
例如:
String parentPath="D:/";
String name="1.txt";
File src=new File(parentPath, name) ;
这里值得注意的是路径表示有三种:
//路径表示形式
String path1="D:\\1.txt";
String path2="D:"+File.separator+"1.txt";//中间这个separator是名称分隔符“/”;而pathSeparator则是路径分隔符“;”
String path3="D:/1.txt";
注意:路径名称不能直接复制电脑上的,D:\1.txt 这样会报错1
getName() 返回文件或目录的名称
getPath() 返回路径名字字符串
isFile() 判断是否是一个文件
isDirectory()判断是否是一个目录
import java.io.File;
import java.io.IOException;
public class Demo03 {
public static void main(String[] args) throws IOException {
File src = new File("D:/1.txt");
System.out.println(src.getName());//返回名称
System.out.println(src.getPath());//如果是绝对路径的话返回完整路径,否则相对路径
System.out.println(src.getAbsolutePath());//返回绝对路径
System.out.println(src.getParent());//返回上一级目录
//System.out.println(src.get);
System.out.println("文件是否存在"+src.exists());
System.out.println("是否可读可写"+src.canWrite()+src.canRead());
System.out.println("");
if(src.isFile()) {
System.out.println("文件");//存在
}else {
System.out.println("文件夹");//不存在
}
//创建新的文件 ,要是已经有了就不新建了 返回失败
File src2=new File("D:/1.txt");
if(!src2.exists()) {
boolean flog=src2.createNewFile();
System.out.println(flog?"成功":"失败");
}
//删除文件
boolean flog=src2.delete();
System.out.println(flog?"成功":"失败");
}
运行结果:
一:读取文件
1:建立联系 File对象 源头(老家)
2:选择流 文件输入流 inputstream Fileinputstream
3:操作: byte[] x=new byte[10] + read()+读取大小
输出
4:释放资源:关闭 .close()
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
//读取文件
public class inputstream {
public static void main(String[] args) {
//1:建立联系 File对象
File src=new File("D:/1.txt");
//2:选择流
InputStream is=null;
try {
is=new FileInputStream(src);
//3:操作不断读取,缓冲数组
byte[] x=new byte[1024];
int cr=0;//接收实际读取大小
try {
//循环读取
while(-1!=(cr=is.read(x))) {
String y=new String(x, 0, cr);
System.out.println(y);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("文件不存在");
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("读取文件失败");
}finally {
if(is!=null) {
try {
is.close();
} catch (IOException e) {
System.out.println("无法关闭");
e.printStackTrace();
}
}
}
}
}
二:写出文件
1:建立联系 File对象 目的地(新家)
2:选择流 文件输出流 outputstream Fileoutputstream
3:操作: write()+flush
输出
4:释放资源:关闭 .close()
//写入数据
public class outputstream {
public static void main(String[] args) {
//1:建立连接 file 目的地
File src= new File("D:/1.txt");
//2:选择流
OutputStream os=null;
//以追加形式写出文件
try {
os=new FileOutputStream(src,true);//注意了 这里的true是说 你第一次写入数据后 如果再执行若你不写true或者写flase就会覆盖上一次的结果,但是若是true则会追加,在后面继续添加
//3:操作
String x="1234567你好呀";
//字符串转字节数组
byte[] data=x.getBytes();
try {
os.write(data, 0, data.length);
os.flush();//强制刷新出去
} catch (IOException e) {
System.out.println("文件写出失败");
e.printStackTrace();
}
} catch (FileNotFoundException e) {
System.out.println("文件不存在");
e.printStackTrace();
}finally {
if(os!=null) {
try {
os.close();
} catch (IOException e) {
System.out.println("关闭失败");
e.printStackTrace();
}
}
}
}
}
三:文件|文件夹的拷贝 程序为桥梁,就是把读取的内容拷贝到写出的目的地里面,两个不同的路径,也就是把前两个结合起来了
1:建立联系 File对象 源头和目的地
2:选择流 文件输入流 inputstream Fileinputstream 文件输出流 outputstream Fileoutputstream
3:操作: byte[] x=new byte[10] + read()+读取大小
write()+flush
4:释放资源:关闭 .close()
文件的拷贝:
//复制文件 就是将前两个合并 先读取后合并
public class copy {
public static void main(String[] args) throws IOException {
String srcpath="D:/1.JPG";
String destpath="D:/4.JPG";
try {
copyfile(srcpath, destpath);
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("404NotFound");
}catch (IOException e) {
e.printStackTrace();
System.out.println("复制失败,关闭流失败");
}
}
public static void copyfile(String srcpath,String destpath) throws IOException{
File src=new File(srcpath);
File dest= new File(destpath);
if(!src.isFile()) {
System.out.println("只能拷贝文件");
}
InputStream is=null;
is=new FileInputStream(src);
OutputStream os=null;
os=new FileOutputStream(dest,true);
//读取1.txt(必须存在且为文件)
byte[] x=new byte[1024];
int cr=0;
while(-1!=(cr=is.read(x))) {
os.write(x,0,cr);
}
//2:copy 将上面读取的写入到3.txt(可以不存在)
os.flush();//强制刷新出去
os.close();
is.close();
}
}
文件夹的拷贝(如果将父目录复制到子目录会报错):
//复制文件夹
public class copydir {
public static void main(String[] args) throws IOException {
String srcpath="G:/1";
String destpath="F:/1";
File src=new File(srcpath);
File dest=new File(destpath);
if(src.isDirectory()) {
dest=new File(destpath,src.getName());
}
copyDirDetail(src, dest);
}
public static void copyDirDetail(File src,File dest) throws IOException {
if(src.isFile()) {//如果是文件 则直接读取复制
FileUtil.copyfile(src, dest);
}else if(src.isDirectory()) {//如果是文件夹
//确保目标文件夹存在
dest.mkdirs();
//这里有一个bug解决
if(dest.getAbsolutePath().contains(src.getAbsolutePath())) {
System.out.println("父目录不能拷贝到子目录中");
return;
}
//获取下一级目录文件
for(File sub:src.listFiles( )) {
copyDirDetail(sub, new File(dest,sub.getName()));
}
}
}
}
字符流(*****)
字符流(只能处理纯文本,全部为可见字符 .txt .html)
一:纯文本读取
1:建立联系
2:选择流 Reader FlieReader
3: 执行操作
4:关闭流
//字符流读取
public class reader {
public static void main(String[] args) {
//建立连接
String path="D:/1.txt";
File src=new File(path);
//选择流
Reader r=null;
try {
r=new FileReader(src);
char[] cr=new char[1024];//这里不是byte 是char
int len=0;
try {
while(-1!=(len=r.read(cr))) {
String s=new String(cr, 0, len);
System.out.println(s);
}
} catch (IOException e) {
System.out.println("文件读取失败");
e.printStackTrace();
}
} catch (FileNotFoundException e) {
System.out.println("文件找不到404");
e.printStackTrace();
}finally {
if(r!=null) {
try {
r.close();
} catch (IOException e) {
System.out.println("关闭流失败");
e.printStackTrace();
}
}
}
}
}
二:纯文本写出
1:建立联系
2:选择流
3:读取write(字符数组,0,长度)+flush
write(字符串)
write(字符|字符串)
4:关闭流
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
//纯文本写出
public class writer {
public static void main(String[] args) {
String path="D:/1.txt";
File dest =new File(path);
Writer wt=null;
try {
wt=new FileWriter(dest,true);
String s="java";
wt.write(s);
wt.append("123");
wt.flush();
} catch (IOException e) {
System.out.println("404");
e.printStackTrace();
}
}
}
三:纯文本拷贝:
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
//只能拷贝纯文本
public class copytxt {
public static void main(String[] args) {
String srcpath="D:/1.txt";
String destpath="D:/4.txt";
try {
copy(srcpath,destpath);
} catch (IOException e) {
System.out.println("拷贝失败");
e.printStackTrace();
}
}
public static void copy(String srcpath,String destpath) throws IOException {
File src=new File(srcpath);
File dest=new File(destpath);
Reader r=null;
r=new FileReader(src);
Writer w=null;
w=new FileWriter(dest,true);
char[] c=new char[1024];
int len=0;
while(-1!=(len=r.read(c))) {
w.write(c, 0, len);
w.flush();
}
r.close();
w.close();
}
}
处理流(*****)
处理流:增强性能、提供性能,节点流之上
一:缓冲流
1:字节缓冲流
BufferedinputStream
BufferedoutputStream
没有新增的方法
// InputStream is=null;
// is=new FileInputStream(src);
// OutputStream os=null;
// os=new FileOutputStream(dest,true);
InputStream is=null;
is=new BufferedInputStream(new FileInputStream(src));
OutputStream os=null;
os=new BufferedOutputStream(new FileOutputStream(src));
/*
* 注意这里加了缓冲流
*/
2:字符缓冲流
Bufferedreader
Bufferedwriter
有新增的方法
//注意这里加了缓冲流,新增了两个方法
r=new BufferedReader(new FileReader(src));
BufferedWriter w=null;
w=new BufferedWriter(new FileWriter(dest,true));
// char[] c=new char[1024];
// int len=0;
// while(-1!=(len=r.read(c))) {
//
// w.write(c, 0, len);
// w.flush();
//
// }
String line=null;
while(null!=(line=r.readLine())) {
w.write(line);
w.newLine();
w.flush();
}
二:转换流
字节流(byte)转为字符流(char) 处理乱码(编码集,解码集)
1:编码与解码的概念
编码 字符 —>编码字符集—>二进制
解码 二进制 —>解码字符集—> 字符
2:乱码问题:
编码和解码的字符集不统一;字节缺少,长度丢失
例如:
import java.io.UnsupportedEncodingException;
public class conver {
public static void main(String[] args) throws UnsupportedEncodingException {
//解码
String str="你好呀";//gbk字符集
//编码 char---byte
byte[] data=str.getBytes();
//默认情况下编码与解码字符集相同
System.out.println(new String(data));
//不相同的情况
try {
byte[] data2 =str.getBytes("utf-8");
System.out.println(data2);
} catch (UnsupportedEncodingException e) {
System.out.println("字符集不相同");
e.printStackTrace();
}
//修改方法
//编码
byte[] data3 = str.getBytes("utf-8");
//解码
System.out.println( new String(data3,"utf-8"));
//就是这俩地都得设置成一样的
//还有一种错误乱码的情况就是字节丢失缺少
String str2="你好呀";
byte[] data4=str2.getBytes();
System.out.println(new String(data4,0,3));
}
}
3:转换流:字节转为字符
输出流OutputStreamWriter 编码
输入流InputStreamReader 解码
BufferedReader r=null;
r=new BufferedReader(new InputStreamReader( new FileInputStream(src),"utf-8"));
BufferedWriter w=null;
w=new BufferedWriter(new OutputStreamWriter( new FileOutputStream(dest),"utf-8"));
关闭流(***)
由于每次都要.close(),太麻烦了
因此编写工具类,实现关闭功能
public class FileUtil {
/*一:
* 工具类关闭流
* 可变参数:... 只能放在形参的最后一个位置,处理方式与数组一致
*/
public static void close( Closeable ... io) {
for(Closeable temp:io) {
if(null!=temp) {
try {
temp.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}//所以在is.close(); os.close(); 这样的关闭方法中 可以用FileUtil.close(is,os);
/*二:
* 使用泛型方法
*/
public static void closseall(T ... io) {
for(Closeable temp:io) {
if(null!=temp) {
try {
temp.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}//所以在is.close(); os.close(); 这样的关闭方法中 可以用FileUtil.closseall(is,os);
}
/*三:
* try {声明}{操作}这是Jdk1.7以后新出的
*/
打印流(***)
PrintStream
一:先了解一下这三个常量
1:system.in 输入流 默认键盘输入 2: system.out 输出流 默认控制台输出 ,一般用于测试或者写日志 , 在system 源码中可以看到 控制台的地址是 FileDescriptor.in/on/err 3: system.err 错误输出流 会和out是不一样的颜色 运行一下就看出来了 如果想要打印输出外面的文件就涉及到 -->重定向 就是说用上面的控制文件 而不是输出输入在控制台 因此就可用到setErr() setIn() setOut()public class Systemio {
public static void main(String[] args) throws FileNotFoundException {
System.out.println("out");
System.err.println("err");
//键盘输入
//Scanner sc=new Scanner(System.in);也就是下面这个
// InputStream is=System.in;
// Scanner sc=new Scanner(is);
// System.out.println(sc.nextLine());
//text2();
//控制台--->文件
System.setOut(new PrintStream(new BufferedOutputStream(new FileOutputStream("D:/5.txt",true)),true));//第一个true早就知道了是每次输入都不覆盖的意思(每次输入追加);所以这里的第二个true 就是让他自动刷新,要不然没内容
System.out.println("aaaaaaaa");//此时运行你会发现5.txt里面木有东西 是因为没有刷新 .flush()
//回到控制台
System.setOut(new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)),true));
System.out.println("back.......");
}
public static void text2() throws FileNotFoundException {
//也可以从文件输出输入
InputStream is2=System.in;
is2=new BufferedInputStream(new FileInputStream("D:/5.txt"));
Scanner sc2=new Scanner(is2);
System.out.println("请输入:");
System.out.println(sc2.nextLine());
}
}
二:PrintStream打印输出流练习:
public class PrintStreamio {
public static void main(String[] args) throws FileNotFoundException {
System.out.println("text");
PrintStream ps=System.out;
ps.println("sjw");//这就是把上面的分解了
//输出到文件
File src=new File("D:/5.txt");
ps=new PrintStream(new BufferedOutputStream(new FileOutputStream(src)));
ps.println("123456");
FileUtil.closseall(ps);//看这个就调用了咱们的工具类 关闭流方法
}
}
其他流(**)
一:节点流
1:字节数组 节点流输入流:ByteArrayInputStream read(byte[]b,int off,int len)+close()
输出流:ByteArrayInputStream write(byte[]b,int off,int len)+toByteArray() 不要使用多态
文件---程序---字节数组
文件输入流
字节数组输出流
字节数组---程序---文件
字节数组输入流
文件输出流
public class byteArrayfile {
public static void main(String[] args) throws IOException {
byte[] data=getBytesFromFile("D:/1.jpg");
toFileFromByteArray(data, "D:/7.jpg");
}
/*
* 文件---程序---字节数组
文件输入流
字节数组输出流
*/
public static byte[] getBytesFromFile(String path) throws IOException {
File src=new File(path);
byte[] dest=null;
InputStream is=new BufferedInputStream(new FileInputStream(src));
//字节数组输出流不能使用多态
ByteArrayOutputStream bos= new ByteArrayOutputStream() ;
byte[] flush=new byte[1024];
int len=0;
while(-1!=(len=is.read(flush))){
dest=bos.toByteArray();//转为字节数组
}
return dest;
}
/*
* 字节数组---程序---文件
字节数组输入流
文件输出流
*/
public static void toFileFromByteArray(byte[] src,String destPath) throws IOException {
//创建源
//目的地
File dest =new File(destPath);
//选择流
//字节数组输入流
InputStream is=new BufferedInputStream(new ByteArrayInputStream(src));
//文件输出流
OutputStream os=new BufferedOutputStream(new FileOutputStream(dest));
//操作不断读取数组
byte[] by=new byte[1024];
int len=0;
while(-1!=(len=is.read(by))) {
os.write(by,0,len);
}
os.flush();
os.close();
}
}
二:处理流
2:基本数据类型+String 保留数据+类型输出流:DataInputStream readxxx
输入流:DataOutputStream writexxx
一般可以结合节点数组使用
注意:所读取的数据类型和顺序必须与目标相同
若不同会报错*EOFException* 意思是说已经读取到末尾 没读取到你指定类型的数据
public class Data {
public static void main(String[] args) throws IOException {
datain("D:/7.txt");
//dataout("D:/7.txt");
}
//读取
public static void datain(String srcpath) throws IOException {
//创建源
File src=new File(srcpath);
//选择流
DataInputStream dis=new DataInputStream(new BufferedInputStream(new FileInputStream(src)));
//操作读取的顺序与写出一致,必须存在才能读取
dis.readDouble();
dis.readInt();
dis.readUTF();
System.out.println(dis.readUTF());
dis.close();
}
public static void dataout(String destpath) throws IOException {
Double y=1.2;
int z=100;
String x="你好";
File dest=new File(destpath);
DataOutputStream dos=new DataOutputStream(new BufferedOutputStream(new FileOutputStream(dest)));
dos.writeDouble(y);
dos.writeInt(z);
dos.writeUTF(x);
dos.flush();
dos.close();
}
}
3:引用类型(对象)保留数据类型
反序列化:输入流 ObjectInputStream readObject
序列化: 输出流:ObjectOutputStream writeObject
先序列化后反序列化 反序列化必须与序列化顺序一致
java.io.NotSerializableException报错 解决方法implements java.io.Serializable
不是所有的属性都需要序列化 若加了transient 此属性就不会被序列化
注意 数组也可以序列化 跟对象一样
```java
public class Objectio {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
//seri("D:/4.txt");
datain("D:/4.txt");
}
//反序列化
public static void datain(String srcpath) throws IOException, ClassNotFoundException {
//创建源
File src=new File(srcpath);
//选择流
ObjectInputStream dis=new ObjectInputStream(new BufferedInputStream(new FileInputStream(src)));
Object obj=dis.readObject();
if(obj instanceof Demo4 ) {
Demo4 de=(Demo4 )obj;
System.out.println(de.getName());//他输出来不会是你好,会是null, 因为他加了transient没有序列化
System.out.println(de.getx());
}
obj=dis.readObject();
int[] arr=(int[])obj;
System.out.println(Arrays.toString(arr));
dis.close();
}
//序列化
public static void seri(String destPath) throws FileNotFoundException, IOException {
Demo4 de=new Demo4 ("你好",100000.2);
int[] arr= {1,2,3};
File dest=new File(destPath);
ObjectOutputStream dos=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(dest)));
dos.writeObject(de);
dos.writeObject(arr);
dos.flush();
dos.close();
}
}
附:
public class Demo4 implements java.io.Serializable{
//不需要序列化就加transient
private transient String name;
private double x;
public Demo4() {
}
public Demo4(String name,double x) {
super();
this.name=name;
this.x=x;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getx() {
return x;
}
public void setx(double x) {
this.x = x;
}
}
结束…
此次学习是对IO流的初步理解,具体的深水区会慢慢探索,若文章笔记内容有错,还请提出指教。。。