0
点赞
收藏
分享

微信扫一扫

java代码-------IO(尚马day18) week5(3)

一叶轻舟okok 2022-03-12 阅读 60

(1)InputStream流(输入流)-----对应读read

class MyClass implements Closeable {

    @Override
    public void close() throws IOException {
        System.out.println("我被关闭了......");
    }
}

public class InputStreamDemo {

    public static void main(String[] args) {
        
    }

    private static void demo6() throws FileNotFoundException {

        FileInputStream inputStream = new FileInputStream("src/info.txt");

        try (inputStream) {
            byte[] bytes = new byte[5];
            //public int read(byte b[], int off, int len)   //read带三个参数的
            //off:指定的索引位置存储字节内容
            //len: 存储字节个数
            int result = inputStream.read(bytes, 0, bytes.length);
            System.out.println(Arrays.toString(bytes));
            System.out.println(result);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void demo5() throws FileNotFoundException {

        //对于输入流而言: read      文件必须要存在的
        FileInputStream inputStream = new FileInputStream("src\\com\\javasm\\io\\InputStreamDemo.java");
        try (inputStream) {
            //读取数据
            byte[] bytes = new byte[1024];      //一般都是1024的整数倍,理论上来说,空间越大,速度越快
            //int result = inputStream.read(bytes);    //read参数为字节数组
            
            //一次读取1024个字节内容 读取到的字节的数据都存储到了bytes数组中
            //result: 维护读取到的有效的字节个数
            //有效的字节的数据是多少个? 不一定是length  
            //System.out.println(result);
            //System.out.println(Arrays.toString(bytes));
            //1.循环遍历字节数组  将每一个字节转换成char  result次
            //2.将字节数组转换成字符串的数据(看不懂的数据转换成看的懂的字符串)
            //String s = new String(bytes, 0, result);
            //System.out.println(s);

            //循环读取指定的文件的数据
            int len;
            while ((len = inputStream.read(bytes)) != -1) {       //还未读到文件末尾
                System.out.print(new String(bytes, 0, len));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void demo4() throws FileNotFoundException {       //抛异常
        
        InputStream inputStream = new FileInputStream("src/info.txt");
        MyClass myClass = new MyClass();
        try (inputStream; myClass;) {         //1.7+之后,可在小括号里加多个需要释放资源的对象
            inputStream.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void demo3() {
        //1.7+ 提供了一种更加优雅的方式"释放流对象",会自动调用close
        //try....with...resources   资源释放就不需要编写了 不需要finally
        try (    
                //try()里放的是需要释放资源的对象,要求这些对象必须实现Closeable
                InputStream inputStream = new FileInputStream("src/info.txt");
                MyClass myClass = new MyClass();   //也实现了Closeable接口
        ) {
            System.out.println(inputStream.read());
        } catch (IOException e) {
            e.printStackTrace();
        }                                //不再需要finally释放资源,已自动调用close  
        //如何证明close被自动关闭   让MyClass实现Closeable接口,并重写close方法。第一次运行try里不加MyClass myClass = new MyClass(); 
        //的代码,然后在try里加该代码,若真的关闭了,自然会走MyClass重写的方法
    }                

    private static void demo2() {
        InputStream inputStream = null;
        try {
            //1.创建字节输入流对象
            inputStream = new FileInputStream("src/info.txt");
            //文件不存在,无法读取
            System.out.println(inputStream.read());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null)
                    inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static void demo1() {
        //读取指定文件里面的数据----> 不要操作中文    read(读)----inputStream输入流
        String filePath = "src/info.txt";
        //读取
        InputStream inputStream = null;
        try {
            //1.创建字节输入流对象 并获得文件字节数据
            inputStream = new FileInputStream(filePath);   //多态创建
            //2.读取流里面字节数据
            /*int data = inputStream.read();    //无参的,一次读一个字节,返一个字节内容     读完所有的字节数据,读到文件末尾,返-1
            //System.out.println("读取到的第一个字节:" + (char)data);
            //循环去读
            while (data != -1) {
                System.out.print((char) data);
                data = inputStream.read();
            }*/
            
            int result;
            while ((result = inputStream.read()) != -1) {
                System.out.print((char) result);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //释放资源
            try {
                if (inputStream != null) inputStream.close();     //不为空关闭
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

(2)OutputStream流(输出流)-----对应写write

只要调close,就会提前flush()。

public class OutputStreamDemo {

    public static void main(String[] args) throws FileNotFoundException {

        //src/a.txt
        //对于输出流  文件不存在?  是否会报错?  不会报错  文件会自动创建(File.createNewFile())
        //一定要保证父级目录要存在   src/demo/a.txt  连父级目录demo都没有,则出错。不可能连父级目录也创建出来
        //读写内容: 出现乱码  编码格式不符
        //字节流读取字符数据,仅对于汉字,可能会出现乱码。
        OutputStream outputStream = new FileOutputStream("src/a.txt", true);   //不加true,默认覆盖。加true,在文件末尾添加
        try (outputStream) {
            outputStream.write(97);   //a
            outputStream.write("张三".getBytes());
            outputStream.write("97".getBytes());
            outputStream.write('\n');
            outputStream.write("我们".getBytes(Charset.forName("UTF-8")));   //在指定格式下编码
            //outputStream.write("世界那么大".getBytes(), 0, 5);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

(3)字节流案例--文件上传

/**
 * @author: sunshine
 * @description:  模拟用户上传头像
 * @data: 2022/3/7  21:26
 * @version: 0.1
 * @since: jdk11
 */
//流程:1.告知文件在哪?--上传文件路径   2.读取用户传的数据,写入服务器中的一个文件里(要保证文件名称唯一)
public class UploadImageDemo {

    private static final String PARENT_DIRECTORY = "upload/user/";  //假设要将文件传到day19里的upload文件夹里的user文件夹里

    public static String upload(String sourceFilePath) throws FileNotFoundException {   //返回值是上传成功后的文件路径    形参是告知的要上传的文件路径
        Objects.requireNonNull(sourceFilePath);
        //文件很大,循环读写文件数据
        //1.读取源文件数据  InputStream
        //2.写入目标文件中  OutputStream
        InputStream inputStream = new FileInputStream(sourceFilePath);
        //获得目标文件名称
        String fileName = sourceFilePath.substring(sourceFilePath.lastIndexOf(File.separator) + 1);   //获得源文件名称,最后\之后的数据
        OutputStream outputStream = new FileOutputStream(PARENT_DIRECTORY+fileName);  //目标文件路径
        try (inputStream;outputStream){
            //循环读写数据
            int len;  //有效字节数
            while ((len=inputStream.read())!=-1){
                outputStream.write(len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("文件上传成功");
        return PARENT_DIRECTORY+fileName;   //PARENT_DIRECTORY+文件名+后缀
    }

    public static void main(String[] args) throws FileNotFoundException {
        String path = "E:\\io\\tom.jpg";   //要上传的文件路径
        System.out.println(upload(path));   //传过去要上传路径,返回上传后的路径。(回显图片)
    }

}

不同用户上传重名文件时:

/**
 * @author: sunshine
 * @description:  模拟用户上传头像
 * @data: 2022/3/7  21:26
 * @version: 0.1
 * @since: jdk11
 */
public class UploadImageDemo {

    private static final String PARENT_DIRECTORY = "upload/user/";

    public static String upload(String sourceFilePath) throws FileNotFoundException {
        Objects.requireNonNull(sourceFilePath);
        InputStream inputStream = new FileInputStream(sourceFilePath);
        //String fileName = sourceFilePath.substring(sourceFilePath.lastIndexOf(File.separator) + 1);
        //保证名称唯一性,用UUID(128位的无符号的16进制的字符串,几乎不可能重复),一般不要其中的-
        String extension = sourceFilePath.substring(sourceFilePath.lastIndexOf("."));
        String targetFileName = UUID.randomUUID().toString().replaceAll("-","")+extension;
        OutputStream outputStream = new FileOutputStream(PARENT_DIRECTORY+targetFileName);
        try (inputStream;outputStream){
            int len;
            while ((len=inputStream.read())!=-1){
                outputStream.write(len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("文件上传成功");
        return PARENT_DIRECTORY+targetFileName;
    }

    public static void main(String[] args) throws FileNotFoundException {
        //String path = "E:\\io\\tom.jpg";
        String path1 = "D:\\io\\tom.jpg";   //另一个用户又上传了一个同名的图片
        System.out.println(upload(path1));
    }

}

若上传大量文件,将文件传到多个目录中:

/**
 * @author: sunshine
 * @description:  模拟用户上传头像
 * @data: 2022/3/7  21:26
 * @version: 0.1
 * @since: jdk11
 */
public class UploadImageDemo {

    private static final String PARENT_DIRECTORY = "upload/user/";

    public static String upload(String sourceFilePath) throws FileNotFoundException {
        Objects.requireNonNull(sourceFilePath);
        InputStream inputStream = new FileInputStream(sourceFilePath);
        //用户量增加,解决所有文件都在同一个目录的问题,用分目录存储图片
        //一般以时间命名目录
        //动态创建目录,目录名以当前时间为目录名称     2022-03-07这样的格式
        String curDate = LocalDate.now().toString();   //当前时间
        //判断目录是否存在
        File directory = new File(PARENT_DIRECTORY,curDate);
        if(!directory.exists()){
            directory.mkdirs();    //若不存在,创建目录
        }

        String extension = sourceFilePath.substring(sourceFilePath.lastIndexOf("."));
        String targetFileName = UUID.randomUUID().toString().replaceAll("-","")+extension;
        OutputStream outputStream = new FileOutputStream(new File(directory,targetFileName));  //这里也变动
        try (inputStream;outputStream){
            int len;
            while ((len=inputStream.read())!=-1){
                outputStream.write(len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("文件上传成功");
        return PARENT_DIRECTORY+curDate+"/"+targetFileName;   //多了一级目录
    }

    public static void main(String[] args) throws FileNotFoundException {
        //String path = "E:\\io\\tom.jpg";
        String path1 = "D:\\io\\tom.jpg";
        System.out.println(upload(path1));
    }

}

若用户量更多,以后还有目录打散(利用哈希表)的方法。


若上传文件很大:

/**
 * @author: sunshine
 * @description:  模拟用户上传头像
 * @data: 2022/3/7  21:26
 * @version: 0.1
 * @since: jdk11
 */
public class UploadImageDemo {

    private static final String PARENT_DIRECTORY = "upload/user/";

    public static String upload(String sourceFilePath) throws FileNotFoundException {
        Objects.requireNonNull(sourceFilePath);
        InputStream inputStream = new FileInputStream(sourceFilePath);
        String curDate = LocalDate.now().toString();
        File directory = new File(PARENT_DIRECTORY,curDate);
        if(!directory.exists()){
            directory.mkdirs();
        }

        String extension = sourceFilePath.substring(sourceFilePath.lastIndexOf("."));
        String targetFileName = UUID.randomUUID().toString().replaceAll("-","")+extension;
        OutputStream outputStream = new FileOutputStream(new File(directory,targetFileName));
        try (inputStream;outputStream){
            //目前是读一个字节就写一个字节,很慢
            //优化,来个缓冲,就是byte[]   (再大的是多任务,多线程完成的)
            byte[] bytes = new byte[1024];  //一次读1024个字节放到字节数组中
            int len;
            while ((len=inputStream.read(bytes))!=-1){
                outputStream.write(bytes,0,len);   //这里用带三个参的,给有效字节,若用write(byte[]),写的东西肯定大于源文件
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("文件上传成功");
        return PARENT_DIRECTORY+curDate+"/"+targetFileName;
    }

    public static void main(String[] args) throws FileNotFoundException {

        long begin = System.nanoTime();     //开始时间,纳秒
        //String path = "E:\\io\\tom.jpg";
        String path1 = "D:\\io\\tom.jpg";
        System.out.println(upload(path1));
        long end = System.nanoTime();
        System.out.println(end-begin);    //计算上传时间
    }

}

大文件,不用缓冲,用高效流(底层自带缓冲,8192)替换也可以:

/**
 * @author: Lisa
 * @className: BufferDemo
 * @description: 高效字节流
 * @date: 2022/3/7 16:35
 * @version: 0.1
 * @since: jdk11
 */
public class BufferDemo {
    
    public static void main(String[] args) throws FileNotFoundException {
        //模拟文件上传:
        long begin = System.currentTimeMillis();
        String path = "E:\\tools\\IntelliJ IDEA\\ideaIU-2020.1.1.exe";
        BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(path));
        BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream("D:\\a.exe"));

        try (inputStream; outputStream) {
            //循环读写 
            int len;
            byte[] bytes = new byte[1024 * 5];   //底层自带数组,若自定义数组
            //自定义的缓冲 >底层的缓冲  就不使用底层的缓冲
            //自定义的缓冲 < 底层的缓冲 8192
            while ((len = inputStream.read(bytes)) != -1) {
                //一次读取一个字节 一次写一次字节
                outputStream.write(bytes,0,len);   //将1个字节写入缓冲,当缓冲满的时候,调用底层的flush,写到文件
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println(end - begin);    //8
    }

}

(4)字符流  

/**
 * @author: Lisa
 * @className: RederDemo
 * @description:
 * @date: 2022/3/7 16:58
 * @version: 0.1
 * @since: jdk11
 */
public class ReaderDemo {

    public static void main(String[] args) {
        try {
            demo2();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void demo2() throws IOException {
        //创建字符输出流对象
        @Cleanup         //close注解
        FileWriter writer = new FileWriter("src/a.txt");   
        writer.write('a');
        writer.write('\n');
        writer.write('好');
        writer.write('\n');
        writer.write(97);
        writer.write("hello world  你好 世界");    

    }

    private static void demo1() throws FileNotFoundException {

        //1.创建字符输入流对象 Reader
        Reader reader = new FileReader("src/info.txt");
        try (reader) {
            //2.循环读取文件数据
            //reader.read();         //一次读取一个字符  -1
            /*int data = reader.read();
            System.out.println((char) data);*/
            /*int len;
            while ((len=reader.read())!=-1){
                System.out.print((char)len);
            }*/

            //reader.read(char[] chs);       一次读取length个字符数据  返回值: 有效的字符个数
           /* char[] chars = new char[20];
            int len = reader.read(chars);
            //将chars数组转字符串
            System.out.println(new String(chars, 0, len));*/
            /*char[] chars = new char[20];
            int len;
            while ((len=reader.read(chars))!=-1){
                System.out.print(new String(chars, 0, len));
            }*/

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

(5)字符流案例

模拟用户注册,持久化保存

/**
 * @author: sunshine
 * @description:
 * @data: 2022/3/7  22:52
 * @version: 0.1
 * @since: jdk11
 */
public class UserDemo {
    public static void main(String[] args) throws IOException {
      userRegister();
    }
    private static int idIndex = 1001;
    private static void userRegister() throws IOException {
        //模拟用户注册:持久化保存用户信息
        //将每个用户信息保存到userInfo.txt     id-name-pass-age   一行存一个信息
        @Cleanup
        FileWriter writer = new FileWriter("src/userInfo.txt",true);   //将用户信息写入文件中
        @Cleanup
        Scanner input = new Scanner(System.in);
        String answer;
        do {
            System.out.println("请录入用户name");
            String name = input.nextLine();
            System.out.println("请录入用户pass");
            String pass = input.nextLine();
            System.out.println("请录入用户age");
            String age = input.nextLine();

            writer.write(String.join("-",String.valueOf(idIndex++),name,pass,age));
            writer.write("\n");   //换行
            writer.flush();   //写一次看一次
            System.out.println("是否继续?y/n");
            answer = input.nextLine();
        } while (Objects.equals("y",answer));
        System.out.println("注册结束");
    }
}

多个用户注册结束,再次注册,id会从1001开始,如何解决?

/**
 * @author: sunshine
 * @description:
 * @data: 2022/3/7  22:52
 * @version: 0.1
 * @since: jdk11
 */
@Data
class UserInfo{
    private Integer id;
    private String name;
    private String pass;
    private Integer age;
}

public class UserDemo {
    public static void main(String[] args) throws IOException {
      userRegister();
    }

    public static List<UserInfo> findAllUser() throws IOException {
        //查询所有用户,获得最后一个用户的id
        //将每一行记录装配成一个个用户对象(读取文件里的每一行记录,分割,再装配)
        List<UserInfo> userInfoList = new ArrayList<>(10);
        @Cleanup
        BufferedReader reader = new BufferedReader(new FileReader("src/userInfo.txt"));
        //String line = reader.readLine();   //读到末尾为null
        String line;
        while ((line=reader.readLine())!=null){
            String[] infoArray = line.split("-");
            UserInfo userInfo = new UserInfo();
            userInfo.setId(Integer.parseInt(infoArray[0]));
            userInfo.setName(infoArray[1]);
            userInfo.setPass(infoArray[2]);
            userInfo.setAge(Integer.parseInt(infoArray[3]));
            userInfoList.add(userInfo);
        }
        return userInfoList;
    }


    private static int idIndex = 1001;
    private static void userRegister() throws IOException {
        //模拟用户注册:持久化保存用户信息
        //将每个用户信息保存到userInfo.txt     id-name-pass-age   一行存一个信息
        @Cleanup
        FileWriter writer = new FileWriter("src/userInfo.txt",true);   //将用户信息写入文件中
        List<UserInfo> userInfoList = findAllUser();
        if(!userInfoList.isEmpty()){
           idIndex=userInfoList.get(userInfoList.size()-1).getId();
        }
        @Cleanup
        Scanner input = new Scanner(System.in);
        String answer;
        do {
            System.out.println("请录入用户name");
            String name = input.nextLine();
            System.out.println("请录入用户pass");
            String pass = input.nextLine();
            System.out.println("请录入用户age");
            String age = input.nextLine();
            //新注册用户信息id,要看之前注册过没有
            writer.write(String.join("-",String.valueOf(++idIndex),name,pass,age));
            writer.write("\n");   //换行
            writer.flush();   //写一次看一次
            System.out.println("是否继续?y/n");
            answer = input.nextLine();
        } while (Objects.equals("y",answer));
        System.out.println("注册结束");
    }
}
举报

相关推荐

0 条评论