24中级 - Java的IO【爬虫项目实战】

383 阅读5分钟

计算机多级体系原理简介

3.png

4.png

文件的本质

  • 一段子节流
    • 文本文件(txt/代码/html等)
    • 二进制文件
  • 每个程序负责解释文件中的字节流
    • 十六进制70,查表man ascii就是p
    • 为什么没有换行,看到2个nl就是换行

5.png

6.png

字节码文件是典型的二进制文件

  • 有大量乱码,cafebabe开头

7.png

  • 什么是io 8.png

8.png

  • 16进制换算2进制特别方便,BCD编码

9.png

InputStream/OutputStream

  • 抽象的输⼊/输出操作,无论是:
    • 文件写入字节流【实战】
    • 从⽹络读取字节流【实战】
    • 从其他什什么破烂玩意读取字节流【实战】 谨记:
  • 如果你不是对文件系统十分熟悉的话,请永远使用绝对路径!!!!
  • 一个字节的范围就是0-255

读取文件字节流

package com.github.hcsp;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;

public class Main {
    public static void main(String[] args) throws IOException {
        // 不能被实例化,有些方法没被实现,找InputStream的子类
        InputStream is = new FileInputStream("/Users/ories/Downloads/java-zhangbo-project/22/0/test/src/main/java/com/github/hcsp/Main.java");
//        int firstByte = is.read();
//        System.out.println(firstByte);
//
//        int secondByte = is.read();
//        System.out.println(secondByte);

        while (true) {
            int b = is.read();
            if (b == -1) {
                break;
            }
            System.out.print((char) b);
        }

    }
}

  • 写入一个字符到某个文件
package com.github.hcsp;

import java.io.*;
import java.util.Arrays;

public class Main {
    public static void main(String[] args) throws IOException {
        OutputStream os = new FileOutputStream("/Users/ories/Downloads/java-zhangbo-project/22/0/test/src/main/java/com/github/hcsp/Main2.java");
        os.write('p');
    }
}
  • 读输出流
public static void main(String[] args) throws IOException {
    ProcessBuilder pb = new ProcessBuilder("ls");
    Process process = pb.start();
    System.out.println((char) process.getInputStream().read());
}

file在java中代表什么

  • 代表一个文件路径,并不代表文件一个对象
    public static void main(String[] args) throws IOException {
        File file = new File("/Users/ories/Downloads/java-zhangbo-project/24/1/1-read-github-pull-requests/src/main/java/com/github/hcsp/http/test1.java");
        File inExistFile = new File("/Users/ories/Downloads/java-zhangbo-project/24/1/1-read-github-pull-requests/src/main/java/com/github/hcsp/http/test3.java");

        // exists判断当前文件是否存在
        file.exists();
        // 是否是文件
        file.isFile();
        // 判断是否是文件夹
        file.isDirectory();
    }

java中的File

  • 不要误会!不要误会!不要误会!
    • File并不代表一个"文件",它只代表一个"路径"
    • 抽象的"文件"路径:文件或者文件夹
  • File的常见方法
    • 绝对路径与相对路径
    • 读/写文件
  • NIO (Java 7+)
    • New IO 新的IO
    • Non-blocking IO 非阻塞IO
  • NIO的Path - 就是旧版本的File

10.png

11.png

归一化文件路径

12.png

java的console

  • 需要java 9

13.png

Java的NIO

  • NIO的定义有两种,1.New IO新的IO 2.Non-blocking IO非阻塞IO
  • NIO的Path - 就是java旧版本的File
  • Path toFile, file可以toPath互相转,Files类比较常用,NIO只需要知道这Files一个类
  • readAllLines不引入第三方库的读取文件

经典的基于IO流的模型的优缺点

14.png

  • java7的nio是基于块,更快1
  • 缓存区解决慢

15.png

  • 多线程解决慢
  • nio的缺点比较复杂

zsh

  • 比较好用的命令行终端

换行符的历史

  • 古老的打印机的换行,
  • windows \r\n 来自古老的打自己
  • linux的是\n

bufferReader和bufferWriter

  • 缓冲区的概念

17.png

  • buffer reader在java里是什么,就是cb的数组

18.png

不要重新做轮子

  • FileUtils
  • IOUtils

课后练习

  • 1
package com.github.hcsp.io;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class FileAccessor {
    public static List<String> readFile1(File file) throws IOException {
        // 声明输出流
        InputStream inputStream = new FileInputStream(file);
        // 声明输出流的缓存
        StringBuffer stringBuffer = new StringBuffer();
        // 读取输出流
        int readInt = inputStream.read();
        // 只要能读取
        while (readInt != -1) {
            // 写入输出流的缓存
            stringBuffer.append((char) readInt);
            readInt = inputStream.read();
        }
        // 将输出流的缓存转换成字符串
        String intputStr = new String(stringBuffer);
        // 对字符串根据空格进行分割,并添加到列表
        List<String> list = Arrays.asList(intputStr.split("\n"));
        // 输入流关闭
        inputStream.close();
        // 返回列表
        return list;
    }


    public static List<String> readFile2(File file) throws IOException {
        // 声明空的数组
        List<String> list = new ArrayList<>();
        // 声明BufferedReader的类对FileReader包装
        BufferedReader bufferedReader = new BufferedReader(new FileReader(String.valueOf(file.toPath())));
        // 读取一行
        String lineStr = bufferedReader.readLine();
        while (lineStr != null) {
            // 将读取的行添加到列表,只要不为空就一直添加
            list.add(lineStr);
            lineStr = bufferedReader.readLine();
        }

        // 关闭bufferedReader
        bufferedReader.close();
        return list;
    }

    public static List<String> readFile3(File file) throws IOException {
        return Files.readAllLines(file.toPath());
    }

    public static void writeLinesToFile1(List<String> lines, File file) throws IOException {
        // 声明文件输出流
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        for (String string : lines) {
            // 获取string的二进制字节流
            byte b[] = string.getBytes();
            // 输出流将二进制
            fileOutputStream.write(b);
            // 输入空白字符
            fileOutputStream.write('\n');
        }
        // 输出流关闭
        fileOutputStream.close();
    }

    public static void writeLinesToFile2(List<String> lines, File file) throws IOException {
        // 用bufferedWriter类包装fileWriter类
        // fileWriter类 传入路径
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(String.valueOf(file.toPath())));
        String write = "";
        for (String string : lines) {
            write += string + "\n";
        }
        // bufferedWriter写入字符串
        bufferedWriter.write(write);
        // 关闭bufferedWriter
        bufferedWriter.close();
    }

    public static void writeLinesToFile3(List<String> lines, File file) throws IOException {
        Files.write(file.toPath(), lines);
    }

    public static void main(String[] args) throws IOException {
//        writeLinesToFile3("dddasd", new File("./1.vsv"));
    }
}
  • 2
package com.github.hcsp.io;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import com.alibaba.fastjson.JSON;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;


public class Crawler {
    // 给定一个仓库名,例如"golang/go",或者"gradle/gradle",读取前n个Pull request并保存至csvFile指定的文件中,格式如下:
    // number,author,title
    // 12345,blindpirate,这是一个标题
    // 12345,FrankFang,这是第二个标题

    // 给定一个仓库名,例如"golang/go",或者"gradle/gradle",返回第一页的Pull request信息
    public static void getFirstPageOfPullRequests(String repo, Integer n, File file) throws IOException {
        // 创建一个default 客户端
        CloseableHttpClient httpclient = HttpClients.createDefault();
        // 发起了一个http Get请求
        StringBuilder target = new StringBuilder("https://api.github.com/repos/" + repo + "/pulls");
        HttpGet httpGet = new HttpGet(String.valueOf(target));
        // 执行这个请求拿到response
        httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)");
        // 传输的类型
        httpGet.addHeader("Content-Type", "application/x-www-form-urlencoded");
        CloseableHttpResponse response = httpclient.execute(httpGet);
        try {
            HttpEntity entity1 = response.getEntity();
            InputStream is = entity1.getContent();
            String html = IOUtils.toString(is, "UTF-8");
            JSONArray JSONArray = JSON.parseArray(html);
            traverse(JSONArray, n, file);
        } finally {
            response.close();
        }
    }

    public static void savePullRequestsToCSV(String repo, int n, File csvFile) throws IOException {
        getFirstPageOfPullRequests(repo, n, csvFile);
    }

    public static void traverse(JSONArray issuesInfoList, Integer n, File file) throws IOException {
        List<String> linesList = new ArrayList<>();
        linesList.add("number,author,title");
        for (int i = 0; i < n; i++) {
            JSONObject account = (JSONObject) issuesInfoList.getJSONObject(i).get("user");
            Integer number = (Integer) issuesInfoList.getJSONObject(i).get("number");
            String title = (String) issuesInfoList.getJSONObject(i).get("title");
            String user = account.getString("login");
            String singleLines = number + "," + user + "," + title;
            linesList.add(singleLines);
            Files.write(file.toPath(), linesList);
        }
        System.out.println(linesList);
    }

    public static void main(String[] args) throws IOException {
//        savePullRequestsToCSV("gradle/gradle", 3, new File("./test3.csv"));
        savePullRequestsToCSV("golang/go", 5, new File("./test8.csv"));
    }
}