Java 操作文件输入流与输出流,具体内容包括 File 类、文件字节流与字符流、缓冲流。最后以网络爬虫实战案例,讲解其具体的使用方式。
输入流、输出流简介
在 Java 中,流是从源到目的地的字节的有序序列。Java 中有两种基本的流——输入流和输出流。输入流与输出流提供了一条通道,使用该通道可以读取源中的数据或者把数据传送到目的地。示意图如下:

Java 中 java.io 包几乎包含了所有操作输入、输出需要的类。Java 把 InputStream 抽象类的子类创建的流对象称作为字节输入流(FileInputStream)、OutputStream 抽象类的子类创建的流对象是字节输出流(FileOutputStream)。再者,Java 把 Reader 的抽象类的子类创建的流对象称作为字符输入流(FileReader),将 Writer 抽象子类创建的流对象称之为输出流(FileWriter);另外,Java 中也提供了更高级的流——缓冲输入流 BufferedReader、输出流 BufferedWriter。在本篇中,将讲解这些操作的使用。
File 类的使用
File 对象主要用来获取文件本身的一些信息,包括文件所在的目录、文件是否可读、文件是否存在、文件长度等等,不会涉及到文件的具体读写操作。

以下是 File 类经常使用的一些方法:

在使用 File 类时,第一步需要创建一个文件对象,使用如下方式进行创建:

File file = new File("data/");

以下是一个具体的案例,大家可以看看该类中一些方法的使用。

File root = new File("data/");
//判断文件是否问一个目录
Boolean is_directory = root.isDirectory();
System.out.println(root.isDirectory());
//如果是一个目录
if (is_directory) {//获取目录下所有文件和目录的绝对路径,得到的是File数组File[] files = root.listFiles(); for ( File file : files ){System.out.println("文件名称为:" + file.getName());System.out.println("文件可读否:" + file.canRead());System.out.println("绝对路径:"+file.getAbsolutePath());System.out.println("文件的长度为:" + file.length());}
}

在上述程序中,data/ 为一个目录,该目录中有两个文件(1.txt 和 2.txt),执行上述程序可得到如下结果:

文件字节流
字节流,处理的单元为1个字节,用于操作字节和字节数组,其能够很好的处理图片、PDF、音频等文件。但使用字节流处理中文,经常会出现乱码,主要原因是一个中文汉字占用了2个字节。因此,在操作包含中文字符的字符串时,不建议使用字节流操作。在 Java 中,字节流类继承自 InputStream 和 OutputStream,其子类主要有 FileInputStream 和 FileOutputStream。

下面显示了四个构造方法,分别是创建文件字节输入流以及文件字节输出流的方法:

//创建文件字节输入流的两种方式
FileInputStream inputStream = new FileInputStream("data/1.txt");
FileInputStream inputStream = new FileInputStream(new File("data/1.txt"));
//创建文件字节输出流的两种方式
FileOutputStream outputStream = new FileOutputStream("data/out.txt");
FileOutputStream outputStream = new FileOutputStream(new File("data/out.txt"));

其中,以字节为单位读写文件主要用到的方法有:

read();  //顺序读取文件的单个字节
read(byte b[]);  //byte数值用于临时成块存放字节
write(byte b[]);//字节写入文件
write(byte b[], int off, int len); //从给定字节数组中起始于偏移量off处写len个字节

读写操作完成之后,需要使用 close() 方法,关闭打开的流。以下给出了一个简单的使用案例:

//创建文件字节输入流与输出流
//FileInputStream inputStream = new FileInputStream("data/1.txt");
FileInputStream inputStream = new FileInputStream(new File("data/1.txt"));
FileOutputStream outputStream = new FileOutputStream("data/out.txt");
//FileOutputStream outputStream = new FileOutputStream(new File("data/out.txt"));
int temp;
//读写操作
while ((temp = inputStream.read()) != -1) {System.out.print((char)temp);outputStream.write(temp);
}
//流的关闭
outputStream.close();
inputStream.close();

文件字符流
在上面一小节中,提到文件字节流不能很好地处理中文字符,这时可以使用字符流操作。与 FileInputStream 和 FileOutputStream 字节流相对应的是 FileReader 和 FileWriter,它们分别继承自 Reader 和 Writer 这两个抽象类。其基本构造方法如下:

//两种文件字符输入流创建方式
FileReader fileReader = new FileReader("data/1.txt");
//FileReader fileReader = new FileReader(new File("data/1.txt"));
//两种文件字符输出流创建方式
FileWriter fileWriter = new FileWriter("data/outtest.txt");
//FileWriter fileWriter = new FileWriter(new File("data/outtest.txt"));

字符输入流和输出流的 read 和 write 方法,以字符为单位读写数据。其基本使用方法与字节流相同。

read();  //顺序读取文件的单个字符
read(char b[]);  //用于临时成块存放字符
write(char b[]);//字符写入文件
write(char b[], int off, int len); //从给定字符数组中起始于偏移量off处写len个字符

以下给出了一个具体的案例程序,其中读和写的文本皆为中文字符:

//两种文件字符输入流创建方式
FileReader fileReader = new FileReader("data/3.txt");
//FileReader fileReader = new FileReader(new File("data/1.txt"));
//两种文件字符输出流创建方式
FileWriter fileWriter = new FileWriter("data/outtest.txt");
//FileWriter fileWriter = new FileWriter(new File("data/outtest.txt"));
int temp;
while ((temp = fileReader.read()) != -1) {System.out.print((char)temp);fileWriter.write((char)temp);
}
fileWriter.close();
fileReader.close();

缓冲流
字节流与字符流都是无缓冲的输入、输出流,每一次的读写都涉及到磁盘的读写操作,相比于内存操作要慢得多。所以,使用字节流和字符流的操作效率要比缓冲流操作低。另外,缓冲流提供了很好的 readLine 操作,即按行操作。在一些机器学习算法的输入中,经常使用到缓冲流的按行读取操作,例如,分词与句子情感计算、主题模型(每一行表示一个文档)等。在网络爬虫中,经常使用到缓冲流来读取需要爬取的 URL 列表以及保存爬取的字符型数据。

Java 中,经常使用到的是 BufferedReader 和 BufferedWriter(缓冲流中的字符流)。其主要构造方法如下:

//输入流
BufferedReader(Reader in, int sz) //创建一个使用指定大小输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in) //创建一个使用默认大小输入缓冲区的缓冲字符输入流
//输出流
BufferedWriter(Writer out, int sz) //创建一个使用给定大小输出缓冲区的新缓冲字符输出流
BufferedWriter(Writer out) //建一个使用默认大小输出缓冲区的缓冲字符输出流

经常使用到的方法是 readLine() 操作,即读取一行。而写操作主要是 write(),下面通过程序带大家了解它们的具体使用方法:

/****** 文件读取第一种方式  ******/
File file = new File("data/3.txt");
//FileReader读取文件
FileReader fileReader = new FileReader(file);
//根据FileReader创建缓冲流
BufferedReader bufferedReader = new BufferedReader(fileReader);
String s = null;
//按行读取
while ((s = bufferedReader.readLine())!=null) {System.out.println(s);
}
//流关闭
bufferedReader.close();
fileReader.close();
/****** 文件读取第二种方式  ******/
//这里简写了,已成了一行。可以添加字符编码
BufferedReader reader = new BufferedReader( new InputStreamReader( new FileInputStream( new File( "data/3.txt")),"utf-8"));
String s1=null;
while ((s1 = reader.readLine())!=null) {System.out.println(s1);
}
//流关闭
reader.close();
/****** 文件写入第一种方式  ******/
/*File file1 = new File("data/bufferedout.txt","gbk");
FileOutputStream fileOutputStream = new FileOutputStream(file1);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
BufferedWriter bufferedWriter1 = new BufferedWriter(outputStreamWriter);*/
/****** 文件写入快捷方式******/
BufferedWriter writer = new BufferedWriter( new OutputStreamWriter( new FileOutputStream( new File("data/bufferedout.txt")),"gbk"));
Map<Integer,String> map = new HashMap<Integer,String>();
map.put(0, "http://pic.yxdown.com/list/2_0_2.html");
map.put(1, "http://pic.yxdown.com/list/2_0_3.html");
map.put(2, "http://pic.yxdown.com/list/2_0_4.html");
//map遍历数据
for( Integer key : map.keySet() ){writer.append("key:"+key+"\tvalue:"+map.get(key));writer.newLine(); //写入换行操作
}
//流关闭
writer.close();

网络爬虫中的文本存储实例
接下来,我们将通过一个具体实战案例,讲解网络爬虫中涉及到的文本操作。爬取的网站为网易汽车某论坛(网址为:http://baa.bitauto.com/CS55/)。

在爬取数据前,应确定要爬取的数据内容,例如我要爬取的是该网页的帖子 ID 以及帖子标题。

接着,根据自己所要爬取的内容,创建 Bean 对象。具体程序如下:

public class PostModel {private String post_id; //帖子idprivate String post_title; //帖子标题public String getPost_id() {return post_id;}public void setPost_id(String post_id) {this.post_id = post_id;}public String getPost_title() {return post_title;}public void setPost_title(String post_title) {this.post_title = post_title;}
}

下一步,确定需要使用的网页请求工具,这里使用较为简单的 jsoup 请求(通过如下 Maven 配置所需 Jar 包):

<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.11.3</version>
</dependency>

在浏览器中,定位所要爬取内容对应的标签(当然,网络抓包是有必要的),如下:

最后,编写获取数据,解析数据,保存数据的程序:

public class CrawlerTest {public static void main(String[] args) throws IOException {//缓冲流的创建,以utf-8写入文本BufferedWriter writer = new BufferedWriter( new OutputStreamWriter( new FileOutputStream( new File("data/crawlerbitauto.txt")),"utf-8"));List<PostModel> data = crawerData("http://baa.bitauto.com/CS55/");for (PostModel model : data) {//所爬数据写入文本writer.write(model.getPost_id() + "\t" + model.getPost_title() + "\r\n");}//流的关闭writer.close();}static List<PostModel> crawerData(String url) throws IOException{//所爬数据封装于集合中List<PostModel> datalist = new ArrayList<PostModel>();//获取URL对应的HTML内容Document doc = Jsoup.connect(url).timeout(5000).get();//定位需要采集的每个帖子Elements elements = doc.select("div[class=line-bg]").select("div[class=postslist_xh]"); //遍历每一个帖子for (Element ele : elements) {String post_id = ele.select("li.bt").select("a").attr("href").split("-")[1].replaceAll("\\D", "");String post_title = ele.select("li.bt").select("a").text();//创建对象和封装数据PostModel model = new PostModel();model.setPost_id(post_id);model.setPost_title(post_title);datalist.add(model);}return datalist;}
}

上述程序执行后,便会发现所爬取采集的数据,已成功保存到了工程目录下的 data/crawlerbitauto.txt 文本中。该文本中的数据截图为:

网络爬虫下载图片实战案例
在采集数据时,有时需要采集图片、Zip 等文件,此时便可以通过字节写入的方式下载这些内容。

以下我们将通过一个实战案例进行说明,所爬取的数据为游讯图库的数据(网址为:http://pic.yxdown.com/list/204.html)。

首先,需要通过抓包确认所爬取的每一张图片对应的 URL 地址。我们发现抓包对应的地址和浏览器检查图片元素对应的地址有所差异,但通过两个地址都可正常访问图片。

下载图片,我们使用的是 HttpClient 请求网页内容的方式(Maven 配置 Jar 包),如下:

 <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient --><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.5</version></dependency>

请求某个具体的 URL,获取实体 HttpEntity,对应的方法如下:

 //请求某一个URL,获得请求到的内容public static HttpEntity getEntityByHttpGetMethod(String url){HttpGet httpGet = new HttpGet(url);//获取结果HttpResponse httpResponse = null;try {httpResponse = httpClient.execute(httpGet);} catch (IOException e) {e.printStackTrace();}HttpEntity entity = httpResponse.getEntity();return entity;}

其中,HttpClient 设置成 private static 变量:

private static  HttpClient httpClient = HttpClients.custom().build();

下面,我写了一个方法,通过给定的图片地址,实现相应图片下载及保存的功能。该方法调用了 getEntityByHttpGetMethod(String url) 方法,具体程序如下:

//任意输入地址便可以下载图片static void saveImage(String url, String savePath) throws IOException{//图片下载保存地址File file=new File(savePath);//如果文件存在则删除if(file.exists()){file.delete();}//缓冲流BufferedOutputStream bw = new BufferedOutputStream(new FileOutputStream(savePath)); //请求图片数据try {HttpEntity entity = getEntityByHttpGetMethod(url);//以字节的方式写入byte[] byt= EntityUtils.toByteArray(entity); bw.write(byt);System.out.println("图片下载成功!");} catch (ClientProtocolException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}//关闭缓冲流bw.close();}

可以看出,下载图片,这里使用的是缓冲流 BufferedOutputStream,并且写入的是字节数组。

最后,是程序的主方法。在主方法中,给定待爬的地址(http://pic.yxdown.com/list/204.html),获取该地址对应的 HTML 内容,解析 HTML 内容获取所有图片的链接地址,即图片对应的 URL。针对每个图片的 URL,调用 saveImage() 图片下载方法,便可成功爬取该页面中的所有图片。具体程序如下:

  public static void main(String[] args) throws IOException{String url = "http://pic.yxdown.com/list/2_0_4.html";HttpEntity entity = getEntityByHttpGetMethod(url);//获取所有图片链接String html = EntityUtils.toString(entity);Elements elements = Jsoup.parse(html).select("div.cbmiddle > a.proimg > img");for (Element ele : elements) {String pictureUrl = ele.attr("src");saveImage(pictureUrl,"image/" + pictureUrl.split("/")[7] );}//测试程序
//        saveImage("http://i-4.yxdown.com/2018/6/11/KDE5Mngp/ae0c2d4d-04fb-4066-872c-a8c7a7c4ea4f.jpg","image/1.jpg");}

使用该主方法,便可成功将图片下载到指定目录下:


便于读者学习,这里提供了另外一种下载任意图片的操作方法,对应的程序如下:

 //另外,一种操作方式static void saveImage1(String url, String savePath) throws UnsupportedOperationException, IOException {//获取图片信息,作为输入流InputStream in = getEntityByHttpGetMethod(url).getContent();byte[] buffer = new byte[1024];BufferedInputStream bufferedIn = new BufferedInputStream(in);int len = 0;//创建缓冲流FileOutputStream fileOutStream = new FileOutputStream(new File(savePath));BufferedOutputStream bufferedOut = new BufferedOutputStream(fileOutStream);//图片写入while ((len = bufferedIn.read(buffer, 0, 1024)) != -1) {bufferedOut.write(buffer, 0, len);}//缓冲流释放与关闭bufferedOut.flush();bufferedOut.close();}

代码:https://github.com/soberqian/FileProcessInCrawler

数据存储方式之 TXT 文本相关推荐

  1. 《iOS取证实战:调查、分析与移动安全》一3.4 数据存储方式

    3.4 数据存储方式 iPhone上的数据以很多方式进行存储.下面的小节涵盖了每一个数据存储的形式以供审查者了解潜在的证据如何定位或恢复. 内部存储: SQLite 数据库文件: 属性列表: 网络: ...

  2. android 存储方式简书,Android的多种数据存储方式

    1. 简介 作为一个完整的应用程序,数据存储操作是必不可少的.现在Android的离线缓存就是通过网络良好状态时将从服务器收到的数据保存到本地.Android系统中主要提供了3种方式进行数据存储,分别 ...

  3. IOS的四种数据存储方式及优劣

    IOS有四种经常使用数据存储方式: 第一种方法:用NSUserDefaults存储配置信息 NSUserDefaults被设计用来存储设备和应用的配置信息.它通过一个工厂方法返回默认的.也是最经常使用 ...

  4. Kooboo CMS技术文档之三:切换数据存储方式

    切换数据存储方式包括以下几种: 将文本内容存储在SqlServer.MySQL.MongoDB等数据库中 将站点配置信息存储在数据库中 将后台用户信息存储在数据库中 将会员信息存储在数据库中 将图片. ...

  5. Android中的5种数据存储方式

    Android中的5种数据存储方式 Android中的5种数据存储方式 数据存储在开发中是使用最频繁的,在这里主要介绍Android平台中实现数据存储的5种方式,分别是: 1 使用SharedPref ...

  6. js cookie 存储checkbox_浏览器数据存储方式总结,网友:“精辟”!

    今天主要来讲下前端的数据存储,说起数据存储,大家肯定第一时间想起cookie,localstorage,sessionstorage,而其实还有userData和IndexedDB这两种数据存储,接下 ...

  7. 【clickhouse】ClickHouse表引擎 MergeTree 索引与数据存储方式 一级索引 二级索引

    1.概述 转载:ClickHouse表引擎 MergeTree 索引与数据存储方式 2.一级索引 MergeTree 主键使用 primary key 定义,定义主键后,会将数据依据 index_gr ...

  8. html存储数据的方法,数据存储方式有哪些

    数据存储方式:1.顺序存储方法,结点间的逻辑关系由存储单元的邻接关系来体现.2.链接存储方法,结点间的逻辑关系由附加的指针字段表示.3.索引存储方法.4.散列存储方法,根据结点的关键字直接计算出该结点 ...

  9. ios应用数据存储方式(偏好设置)

    iOS开发UI篇-ios应用数据存储方式(偏好设置) 一.简单介绍 很多iOS应用都支持偏好设置,比如保存用户名.密码.字体大小等设置,iOS提供了一套标准的解决方案来为应用加入偏好设置功能 每个应用 ...

最新文章

  1. PCL:从法线计算到曲率计算并可视化
  2. cocos2d ccLayer响应触摸事件方法:CCStandardTouchDelegate 与 CCTargetedTouchDelegate
  3. mysql 集群怎么卸载节点_Greenplum移除节点
  4. 不超过20位的小数正则_意甲身价最贵的20位球星,国米多达7人超过尤文,夺冠成硬任务...
  5. 「译」JUnit 5 系列:环境搭建
  6. caffe to pytorch
  7. 【转】eclipse中window-preference选项中没有tomcat的解决方法
  8. Uva 10305 - Ordering Tasks
  9. scoped_ref
  10. 中兴事件不会对中国高科技产生什么改变
  11. python book.save_Python之操作excel
  12. php html页面显示乱码怎么解决方法,html网页乱码原因以及解决办法
  13. 《创业维艰》笔记 2
  14. nios ii小实验——SDRAM读写
  15. 【盘点】最受欢迎十大中国风歌曲
  16. excel保存快捷键_Excel快升效率的快捷键
  17. UE4中程序驱动的LookAt动画
  18. MT【109】线面角最大时为二面角平面角
  19. mysql3306端口被占用无法终止_Mysql3306端口被占用无法启动解决办法.doc
  20. 专业能力一般的应届本科生,该如何准备面试

热门文章

  1. 从0开始安装fedora23的笔记-- 以及使用fedora的常规问题
  2. 用了filter之后html乱码,使用Filter解决中文乱码问题
  3. 功能测试_大屏常见测试点
  4. 学生无线耳机哪款好?两百左右适合学生党的无线耳机推荐
  5. 五险一金的具体含义及社会保险查询
  6. cmake中添加引用动态链接_macos - CMake:MacOS上动态链接资源的运行时错误(dyld:未加载库) - SO中文参考 - www.soinside.com...
  7. yum源配置方法一(阿里云源)
  8. WebStorm去掉编辑区的竖线
  9. cnpm : 无法加载文件 C:\Users\hp\AppData\Roaming\npm\cnpm.ps1,因为在此系统上禁止运行脚本【已解决】
  10. AI入坑——WIN7或者10下Anaconda3.7+tensorflow+pycharm环境配置