java中IO相关知识点

IO:
    在整个java.io包中最重要的就是5个类和3个接口,掌握了这些IO的核心操作
    5个类:
        1.File类:数据源,文件类
        2.InputStream:字节输入流(我们操作的数据有两种:字符跟字节)
        3.OutputStream:字节输出流
        4.Reader:字符输入流
        5.Writer:字符输出流
    3个接口:文件不是直接存在java中,而是存在硬盘中,那这个硬盘就需要操作系统去操作,因此java程序需要跟操作系统进行交流,
    当java已经读完了这个文件,需要告诉操作系统可以释放你操作系统该文件的资源了,这里就涉及到流关闭接口了。
        1.Closeable:关闭流接口
        2.Flushable:刷新流接口
        3.Serializable:序列化接口
        当我们手上拿到一个对象的时候,如果放在内存中,当电脑一关,数据就没了,因此为了便于对对象的传输,定期
        将其存储到存储文件中,这时候我们就把这种存储对象称作序列化。
        
流分类1:(按直接操作数据源还是间接操作数据源来分)
    字节流:直接从数据源或目的地读写数据
    处理流(包装流):不直接连接到数据源或目的地,是其他流进行封装。目的主要是简化操作和提高性能。
    节点流和处理流的关系:
        1.节点流处于io操作的第一线,所有操作都必须通过他们进行;
        2.处理流可以对其他流进行处理(提高效率或操作灵活性)。
流分类2:按数据类型分为字节流跟字符流(底层还是基于字节流操作,自动搜索了指定码表)。


File类:
    separator  是路径分隔符
        建议用这种方式:
        1.String path = "E:/APP/"  用/这种,虽然也可以用\但需要转义,也即\\
        2.String path = "E:"+File.separator+"APP"+File.separator  这里File.separator就是/
    
    //构建File对象
        1.    
        String path = "E:/app/Java/jre/README.txt";
        File src = new File(path);
        System.out.println(src.length());
        2.只要能拼起来一条路径就行
        File src1 = new File("E:/app/Java/","jre/README.txt");
        System.out.println(src1.length());
        3.
        File src2 = new File(new File("E:/app/Java/"),"jre/README.txt");
        System.out.println(src2.length());

    API:
    pathSeparator separator:路径|路径分隔符
    构造器:没有盘符以user.dir作为相对路径
        File(String parent,String child)
        File(File parent,String child)
        File(String name)
    文件名、路径名:
        getName()、getPath()、getAbsolutePath()、getParent()
    判断状态:File对象可能不存在,如果存在就要么是文件,要么是文件夹
        exists()、isFile()、isDirectory()
    文件长度:length()是能取到文件的长度的(字节长度),但是取不到文件夹的长度,因此length=0存在两种情况,要么是文件夹,要么文件不存在
        length()
    创建新文件、删除文件:
        createNewFile() 不存在才能创建成功,如果存在就不能创建成功、delete()
    创建目录,如果父目录不存在一同创建:
        mkdir():确保上级目录存在,不存在创建失败 mkdirs():上级目录可以不存在,不存在一同来创建
    下级名称:是下一级,不是子孙级,如果要子孙级就采用递归,自己调自己
        list()
    下级File:
        listFiles()    
    根路径:
        listRoots()
        
递归输出子孙级的文件名称:
 public static void PrintName(File s,int level){
        for(int i=0;i<level;i++){
            System.out.print("+");
        }
        System.out.println(s.getName());
        if(!s.exists()){
            return;
        }else if(s.isDirectory()){
            File[] next = s.listFiles();
            for(File s1:next){
                PrintName(s1,level++);
        } 
        }
    }    

由字符到字节叫编码,由字节到字符叫解码    

标准步骤:数据源(new File)->选择流(FileInputStream)->操作(读还是写)->释放资源(close)
将一个文件复制到另一个文件,通过文件输入流和文件输出流合二为一进行
public class TestCopyFile {
    public static void main(String[] args) {
        File src = new File("dest.txt");
        File dest = new File("Aftercopy1.txt");
        InputStream is = null;
        OutputStream os = null;
        try {
            is = new FileInputStream(src);
            os = new FileOutputStream(dest,true);
            //也可以使用分段读取
            byte[] flush = new byte[1024];
            int len = -1;
            while ((len = is.read(flush)) != -1) {
                os.write(flush,0,len);  //我这里容易出问题
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

文件字符输出流与文件字节输出流不同之处在于对于一个String类型的str,字符输出流是字符->字符数组(msg.toCharArray),
字节输出流是字符->字节数组(编码,msg.getBytes()实现).

文件字符输出流有三种输出方式:String msg = "我爱我家"
    1.转换成字符数组
    Char[] datas = msg.toCharArray();
    writer.write(datas,0,datas.length);
    2.直接输出字符
    writer.write(msg);
    writer.flush();
    3.使用append方法来:
    writer.append(msg).append()....可以链式追加,类似之前StringBuilder中的insert方法
    

我们前面所涉及到的FileInputStream FileOutputStream FileReader FileWriter都是存放在硬盘上的文件(源头),java虚拟机是
无权直接访问的,必须要借助os操作系统,借助完之后需要跟它通知释放资源。那么接下来将源头从文件换成另外一个源头,
换成我们电脑上的一块内存,也就是所谓的字节数组,这个字节数组(ByteArray),要么把它看成是同个电脑上的一块内存,要么把它看成是
网络上或者服务器上的一块内存,不再是文件了,而是内存,既然是内存,那么java是可以直接访问的了,也就与操作系统无关了。
所以这个东西是由垃圾回收(GC)来释放了,所以字节数组也就不用关闭了。
任何东西都可以转换成字节数组,但字节数组是内存,所以有限不能太大。
    1.创建源:字节数组,不要太大 byte[] src = "msg".getBytes();
    2.选择流:ByteArrayInputStream(src);
    3.操作
    4.释放资源:可以不用处理
    
字节数组
输出流是有自己的新增方法的toByteArray,所以可以直接通过toByteArray方法或toString直接获取数据
 * 测试字节数组流输出
 * 创建源:内部维护
 * 选择流:不关联源
 * 操作:
 * 释放资源:可以不用

public class TestByteArrayOutputStream {
    public static void main(String[] args) {
        byte[] src = "talk is cheap show me the code".getBytes();
        ByteArrayOutputStream os = null;
        try{
            os = new ByteArrayOutputStream();
            os.write(src);
            byte[] dest = os.toByteArray();
            String result = new String(dest);
            System.out.println(result);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


文件与文件之间是可以直接通过FileInputStream FileOutputStream相互中转,那么文件到字节,字节到文件该怎么实现呢?
字节缓冲流:BufferedInputStream     BufferedOutputStream  
字符缓冲流:BufferedReader  BufferedWriter
缓冲流的存在提高了操作的性能,读写的性能,因为IO的操作是影响性能的一个瓶颈,所以内部维护了个缓冲区。
缓冲流只需要套在字节流上,不管怎么套,最底层一定是个节点流,后期这个流一层一层的该怎么释放呢,释放规则为从里到外释放。
多层的时候释放只需要释放最外层的那个流,它内部会自动找到最里层的节点流进行释放。如果想手动一个一个释放,那规则就是从里到外。
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("dest.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(("dest.txt")));
只要用新增方法,就不要用多态,不要使用父类指向子类引用
BufferedReader reader = new BufferedReader(new FileReader("dest.txt"));
        String line = null;
        while((line = reader.readLine())!=null){
            System.out.println(line);
        }
    这里的readLine与之前的read不一样了(逐行读取)
BufferedWriter writer = new BufferedWriter(new FileWriter("dest.txt"));
        writer.newLine();可以不需要自己手动补充\r\n了
转换流:        
    InputStreamReader/OutputStreamWriter:是字节流与字符流之间的桥梁,能将字节流转换为字符流,并且能为字节流指定字符集,
    可处理一个个的字符,但前提是给转换流的全是纯文本的内容,在处理流的过程中,可以指定字符集
建议:一般的,涉及到字符串,凡涉及到字符串的,就都加个Buffered


数据流:
    DataInputStream & DataOutputStream 主要作用是处理基本数据类型,和字符串的,说白了就是它不仅保留了数据,还保留了数据类型
    就可以直接获取数据类型,而不需要强制转换类型
对象流:
    ObjectInputStream(反序列化) & ObjectOutputStream(序列化) 有个特殊的叫法:序列化Serialization和反序列化(Deserialization)
    不是所有的对象都可以序列化的,必须实现Serialization接口
    对象经序列化后进入文件、数据库或内存中,然后再经过反序列化成为对象。
打印流:
    PrintStream,是个装饰流
    PrintStream ps = System.out;
    ps.println("打印流");
    ps.close();
    
    //重定向输出端
    PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream("print.txt")),true);
    System.setOut(ps);
    System.out.println("change");
    //重定向回控制台
    System.setOut(new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)),true));
    System.out.println("i am back!!!");
    
    PrintStream还有个兄弟,PrintWriter,比较类似
    
RandomAccessFile:随机访问,之前的都是顺序访问的
    
多个class文件-》jar包
多个jar包-》组件
多个组件-》框架

之前学的IO所有关于读取文件写文件都可以通过FileUtils包实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值