黑马程序员--IO(File类、Properties、IO中其他的一些常用流、字符编码)

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-
File类
将文件或文件夹封装成对象,方便对文件与文件夹的属性信息进行操作

File对象可以作为参数传递给流的构造函数

File类常见方法

1.创建

boolean createNewFile()在指定位置创建文件,如果文件已经存在,则不创建文件,返回false
                        此方法和输出流不一样,输出流对象一建立就会创建文件。如果文件已存在,则覆盖。
boolean mkdir() 创建文件夹
boolean mkdirs() 创建文件夹(多级,包括必须的且不存在的父目录)    

2.删除

boolean delete(); 删除文件, 如果文件在使用中,删除失败,返回false
void deleteOnExit();在程序退出时删除文件。

3.判断

boolean canExcute();判断文件是否可执行
boolean exists(); 文件是否存在    <--重点方法

boolean isDirectory(); 判断对象是否是目录
boolean isFile(); 判断对象是否是文件,另外名称带.***的不一定是文件也有可能是目录 
注意:在判断文件对象是否是文件或目录时,必须先判断该文件封装的内容是否存在
      通过exists();                <--开发时必须注意
boolean isHidden(); 判断是否是隐藏的  一般只操作非隐藏的文件,但是java是如果是文件就取出,所以操作时要注意判断一下
boolean isAbsolute(); 判断是否是绝对路径

4.获取信息

String getName();
String getPath(); 封装的是什么路径,就拿到什么路径
String getParent(); 获取父目录,该方法返回的是绝对路径中的文件父目录。
                    如果获取的是相对路径,返回null
                    如果相对路径中有上一层目录,那么该目录就是返回结果。
String getAbsolutePath();
File getAbsolutePath(); 
long lastModify();
long getLength();

5.重命名

boolean renameTo(File dest); 重新命名此抽象路径名表示的文件(有类似剪切的功能)。 

6.列出目录或文件

String[] list() 
      返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。 
String[] list(FilenameFilter filter) 
      返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录。 
File[] listFiles() 
      返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。 
File[] listFiles(FileFilter filter)  //学的时候感觉挺难理解的
      返回抽象路径名数组,这些路径名表示此抽象路径名表示的目录中满足指定过滤器的文件和目录。 
static File[] listRoots() 
      列出可用的文件系统根。 (列出盘符C:\,D:\,E:\  ...)

FilenameFilter的应用方法:

    /*
    需求:列出指定目录的所有.java文件
    */
    public static void listDemo()
    {
        File f=new File("E:\\java0304\\day14");
        String[] s=f.list(new FilenameFilter(){
            public boolean accept(File f,String name)
            {
                return name.endsWith(".java");
            }
        });
        for(String name:s)
        {
            System.out.println(name);
        }
    }

列出指定目录下的所有内容:

    public static void showFile(File f)
    {
        File[] files=f.listFiles();

        for (int i=0; i<files.length; i++)
        {
            if(files[i].isDirectory())
                showFile(files[i]);
            else
                System.out.println(files[i]);
        }
    }

删除带内容的目录:

    /*
    删除带内容的目录
    删除原理:
    在window中,删除目录从里面往外删除
        既然是从里往外删除,就需要用到递归

    java 删除文件不走回收站
    */
    public static void removeDir(File dir)
    {
        File[] files=dir.listFiles();
        for (int i=0; i<files.length; i++)
        {
            if(!file[i].isHidden()&&files[i].isDirectory())
                removeDir(files[i]);
            else 
                System.out.println(files[i]+"..."+files[i].delete());
        }
        System.out.println(dir+"..."+dir.delete());
    }
}

File综合练习:

/*
将一个指定目录下的java文件的绝对路径存储到一个文本文件当中
即建立一个java文件列表清单

思路:
1.对指定目录进行递归
2.获取递归过程中所有的java文件的路径
3.将这些路径村吃到集合中
4.将集合中的数据写入到一个文件中

持久化存储文件
*/
import java.io.*;
import java.util.*;
class JavaFileList 
{
    public static void main(String[] args) throws IOException
    {
        File dir=new File("E:\\java0304");
        List<File> list=new ArrayList<File>();
        fileToList(dir,list);
        //System.out.println(list.size());
        BufferedWriter bufw=new BufferedWriter(new FileWriter("E:\\java0304\\list.txt"));
        for (File file:list)
        {
            bufw.write(file.getAbsolutePath());
            bufw.newLine();
            bufw.flush();
        }
        bufw.close();
        System.out.println("over!!!!");
    }

    public static void fileToList(File dir,List<File> list)
    {
        File[] files=dir.listFiles();
        for (File file:files)
        {
            if(file.isDirectory())
                fileToList(file,list);
            else
            {
                if(file.getName().endsWith(".java"))
                    list.add(file);
            }
        }
    }
}

递归:
函数自身调用自身。
递归使用时应注意:

1.必须限定条件
2.要注意递归的次数避免内存溢出

Properties类:
Properties是hashtable的子类,也就是说它具备map集合的特点。而且它里面存储的键值对都是字符串,Properties是集合和IO技术相结合的结合容器。

该对象的特点:可以用于键值对形式的配置文件

Properties类获取set集合方法

public Set<String> stringPropertyNames();  //JDK1.6版本之后才出现
之前的版本使用的是
Enumeration<?> propertyNames();方法遍历

Object setProperty(String key, String value) 设置元素
void load(InputStream inStream)  加载字节流对象
void load(Reader reader) 加载字符流对象
void store(OutputStream out, String comments) //与load对应 ,comments是注解信息,不会被load加载
void store(Writer writer, String comments)  

load与store:

    public static void loadDemo()throws Exception
    {
        Properties prop=new Properties();
        FileInputStream fis=new FileInputStream("info.txt");
        prop.load(fis); 
        prop.setProperty("zhangsan",88+"");
        FileOutputStream fos=new FileOutputStream("info.txt");
        prop.store(fos,"haha");//文件内的内容改变,haha为注解前面带有#不会被load加载
        prop.list(System.out);
        fos.close();
        fis.close();
    }

使用Properties,记录程序运行次数,超过指定次数,拿钱:

/*
需求:记录程序运行的次数,如果程序运行超过5次,则输出提示信息
*/
import java.io.*;
import java.util.*;
class RunCount 
{
    public static void main(String[] args) throws IOException
    {
        Properties prop=new Properties();

        File file=new File("run.ini");
        if(!file.exists())
            file.createNewFile();

        FileInputStream fis=new FileInputStream(file);
        prop.load(fis);

        int count=0; 

        String value=prop.getProperty("time");
        if(value!=null)
        {
            count=Integer.parseInt(value);
            if(count>=5)
            {
                System.out.println("免费试用次数已用尽,想继续使用,拿钱来!");
                return;
            }   
        }
        count++;
        prop.setProperty("time",count+"");

        FileOutputStream fos=new FileOutputStream(file);
        prop.store(fos,"hehe");
        fos.close();
        fis.close();
    }
}

IO包中的其他流对象
打印流
该流提供了打印方法,可以将各种数据类型都原样打印

PrintWriter 字符打印流   //以后很常用
    构造函数可以接收的参数类型:
    1.file对象 File
    2.字符串路径 String
    3.字节输出流 OutputStream    
    4.字符输出流 Writer
PrintStream 字节打印流
    构造函数可以接收的参数类型:
    1.file对象 File
    2.字符串路径 String
    3.字节输出流 OutputStream
    PrintStream(OutputStream o,autoFlush); 使用此方法构造,程序调用println,printf,format方法将自动刷新
    提供了println()方法

练习:使用打印流将键盘录入的字母的大写写到指定文件当中

    public static void main(String[] args) throws IOException
    {
        //获取键盘录入
        BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));

        PrintWriter out=new PrintWriter("a.txt");

        String line=null;
        while((line=bufr.readLine())!=null)
        {
            if("over".equals(line))
                break;
            out.println(line.toUpperCase());
        }
        out.close();
        bufr.close();
    }

序列流
SequenceInputStream
多个流进行合并
练习:将多个文件合并成一个文件

    public static void main(String[] args) throws IOException
    {
        Vector<InputStream> v=new Vector<InputStream>();
        v.add(new FileInputStream("1.mp3"));
        v.add(new FileInputStream("2.mp3"));
        v.add(new FileInputStream("3.mp3"));
        SequenceInputStream sis=new SequenceInputStream(v.elements());
        BufferedOutputStream bufi=new BufferedOutputStream(new FileOutputStream("合并练习.mp3")); 
        byte[] buf=new byte[1024*3];
        int len=0;
        while ((len=sis.read(buf))!=-1)
        {
            bufi.write(buf,0,len);
            bufi.flush();
        }
        bufi.close();
        sis.close();
    }

能合并就得能切割。
切割文件:

/*
切割文件
切割文件....合并文件
*/
import java.io.*;
import java.util.*;
class SplitFile 
{
    public static void main(String[] args) throws IOException
    {
        //splitFile();
        merge();
    }

    public static void merge()throws IOException
    {
        ArrayList<FileInputStream> al=new ArrayList<FileInputStream>();

        for (int i=1; i<6; i++)
        {
            al.add(new FileInputStream("path\\"+i+".heh"));
        }

        final Iterator<FileInputStream> it=al.iterator();
        Enumeration<FileInputStream> en=new Enumeration<FileInputStream>()
        {
            public boolean hasMoreElements() 
            {
                return it.hasNext();
            }
            public FileInputStream nextElement()  
            {
                return it.next();
            }
        };

        SequenceInputStream sis=new SequenceInputStream(en);
        FileOutputStream fos=new FileOutputStream("path\\music.mp3");
        byte[] buf=new byte[1024*1024];
        int len=0;
        while ((len=sis.read(buf))!=-1)
        {
            fos.write(buf,0,len);   
        }
        fos.close();
        sis.close();
    }

    public static void splitFile()throws IOException
    {
        //关联一个文件
        FileInputStream fis=new FileInputStream("1.mp3");

        FileOutputStream fos=null;

        byte[] buf=new byte[1024*1024];

        int len=0;
        int count=1;
        while ((len=fis.read(buf))!=-1)
        {
            fos=new FileOutputStream("path\\"+(count++)+".heh");//可以定义成任意后缀名
            fos.write(buf,0,len);
            fos.close();
        }
        fis.close();
    }
}

操作对象的流
ObjecInputStream
ObjectOutputStream
被操作的对象需要实现Serializable标记接口
使用这些流,可以把对象存入硬盘,称为对象的持久化。

可序列化类可以通过声明名为 "serialVersionUID" 的字段
(该字段必须是静态 (static)、最终 (final) 的 long 型字段)
显式声明其自己的 serialVersionUID:
 ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;自己不声明,系统会自己产生一个uid,uid是根据类中的成员得出来的,类中的成员发生变化,uid也会发生变化。比如类中某个成员的修饰符由public变为privateuid就发生了变化。

可以通过自定义一个uid,不让uid发生变化

静态成员是不能被序列化的。
可以给非静态成员加上transient关键字,不让该变量被序列化

将对象写入文件并读取:

import Java.io.*;
class Person implements Serializable
{
    private String name;
    private int age;
    Person(String name,int age)
    {
        this.name=name;
        this.age=age;
    }
    public String toString()
    {
        return new String(name+"...."+age);
    }
}
class ObjectStreamDemo 
{
    public static void main(String[] args) throws Exception
    {
        //writeObject();
        readObject();
    }

    public static void readObject()throws Exception
    {
        ObjectInputStream ois=
            new ObjectInputStream(new FileInputStream("obj.object"));
        Person p=(Person)ois.readObject();
        System.out.println(p);
        ois.close();
    }

    public static void writeObject()throws Exception
    {
        ObjectOutputStream oos=
            new ObjectOutputStream(new FileOutputStream("obj.txt"));
        oos.writeObject(new Person("zhangsan",18));
        oos.close();
    }
}

管道流

管道流:
PipedInputStream
PipedOutputStream
输入输出可以直接进行连接,通过结合线程使用
管道流用法示例:

/*
管道流:
PipedInputStream
PipedOutputStream
输入输出可以直接进行连接,通过结合线程使用

*/
import java.io.*;

class Read implements Runnable
{
    private PipedInputStream pis;

    Read(PipedInputStream pis)
    {
        this.pis=pis;
    }
    public void run()
    {
        try
        {
            byte[] buf=new byte[1024];
            int len=pis.read(buf);
            String s=new String(buf,0,len);
            System.out.println(s);
            pis.close();
        }
        catch (Exception e)
        {
            throw new RuntimeException("管道流读取失败");
        }
    }
}
class Write implements Runnable
{
    private PipedOutputStream pos;
    Write(PipedOutputStream pos)
    {
        this.pos=pos;
    }

    public void run()
    {
        try
        {
            pos.write("哥们来了".getBytes());
            pos.close();
        }
        catch (Exception e)
        {
            throw new RuntimeException("管道流写入失败");
        }
    }
}
class  PipedStreamDemo
{
    public static void main(String[] args) throws Exception
    {
        PipedOutputStream pos=new PipedOutputStream();
        PipedInputStream pis=new PipedInputStream();
        pis.connect(pos);
        Read r=new Read(pis);
        Write w=new Write(pos);
        new Thread(r).start();
        new Thread(w).start();
    }
}

RandomAccessFile
访问随机文件,自身具备读写的方法
通过skipBytes(int x),seek(int x)来达到随机访问
该类不算是IO体系中的子类,而是直接继承自Object,但是他是IO包中的成员。因为它具备读和写的功能。
该类内部封装了一个数组,而且通过指针对数组的元素进行操作。
可以通过getFilePointer获取指针位置,
同时可以通过seek改变指针位置。

其实完成读写的原理就是内部封装了字节输入流和输出流。

局限性:
通过构造函数可以看出该类只能操作文件。而且操作文件还有模式
RandomAccessFile(String Filename,String mode); mode模式: 只读r,读写rw,rws,rwd
RandomAccessFile(File file, String mode)

如果模式为只读r,不会创建文件,回去读取一个已经存在的文件。如果文件不存在,会出现异常。
该对象要操作的文件不存在,会创建。
如果存在则会覆盖。

此类需掌握:

1.模式
2.可以直接写入基本数据类型
3.可以通过seek方法改变指针的位置,指定数据的读取和写入

对文件写入数据后读取:

import java.io.*;
class RandomAccessFileDemo 
{
    public static void main(String[] args) throws Exception
    {
        //writeFile();
        //readFile();
        writeFile_2();
    }
    public static void readFile()throws Exception
    {
        RandomAccessFile raf=new RandomAccessFile("ran.txt","r");
        //raf.write("hehe".getBytes());模式为r,运行写的操作报错

        //调整对象中的指针。想指哪就指哪
        //raf.seek(8);

        //跳过指定的字节数,只能往后跳。
        raf.skipBytes(8); 

        byte[] buf=new byte[4];
        raf.read(buf);
        String name=new String(buf);

        int age=raf.readInt();
        System.out.println(name+"..."+age)  ;
        raf.close();
    }

    public static void writeFile_2()throws Exception
    {
        RandomAccessFile raf=new RandomAccessFile("ran.txt","rw");
        raf.seek(8*0);//也可以修改文件的内容
        raf.write("周七".getBytes());
        //raf.write(258);//write方法只写出了int的后8位,数据丢失
        raf.writeInt(65);//写入32位
        raf.close();
    }

    public static void writeFile()throws Exception
    {
        //如果文件存在则覆盖 
        RandomAccessFile raf=new RandomAccessFile("ran.txt","rw");

        raf.write("张三".getBytes());
        //raf.write(258);//write方法只写出了int的后8位,数据丢失
        raf.writeInt(97);

        raf.write("李四".getBytes());
        //raf.write(258);//write方法只写出了int的后8位,数据丢失
        raf.writeInt(88);
        raf.close();
    }
}

操作字节数组的流对象

ByteArrayInputStream  在构造时,需接收数据源。源是一个字节数组
    此流关闭无效,不抛异常
ByteArrayOutputStream 在构造时,不用定义数据目的。因为该对象内部封装了可变长度的字节数组
    此流关闭无效,不抛异常
writeTo(OutputStream os);

因为这两个流对象都操作数组,并没有使用系统资源。所以不用进行close()。
即使关闭了,该流里面的方法仍能继续使用。

操作字符数组的流对象

    CharArrayReader
    CharArrayWriter

操作字符串的流对象

    StringReader
    StringWriter

操作基本数据类型的流

与上面的几种流操作类似 特殊的地方是里面有个writeUTF()和readUTF
DataInputStream
DataOutputStream
使用writeUTF写的数据只能用readUTF读取。

字符编码:
常见的编码表:

ASCII:美国标准信息交换码
 用一个字节的7位表示
ISO8859-1:
 用一个字节的8位表示 
GB2312:中国的中文编码表

GBK:中国的中文编码表的升级,融合了更多的中文字符号

Unicode:国际标准码融合了多种文字
    所有文字都用两个字节来表示,Java语言使用的就是Unicode
UTF-8:最多用三个字节来表示一个字符

编码:字符串变成字节数组
String–>byte[]
str.getBytes();//默认编码表
str.getBytes(byte[],charsetName);//指定编码表
str.getBytes(charsetName)//指定编码表
解码:字节数字变成字符串
byte[]–>String new String(byte[]);

String s="你好";
byte[] b1=s.getBytes("GBK");//编码
System.out.println(Arrays.toString(b1));
String s1=new String(b1,"ISO8859-1");//指定解码表解码

一定要小心的部分:
GBK编码
–>用ISO8859-1解码出错,想要重新按照GBK解析,只能对用ISO8859-1解码出来的字符串重新用ISO8859-1编码,再用GBK解码
–>用UTF-8解码出错,出错之后就不能再用UTF-8编回去了,在服务器应用是发现解码出错都可以在编回去在读出就行了,因为服务器用的是ISO8859-1。

特别注意:”联通”这个字符串的GBK编码方式与UTF-8的编码表形式一样,如果这两个字符在txt文件最开头,按照GBK存储,记事本会按照UTF-8码表解析。为了避免这种情况,可以在联通前边加上个汉字。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值