笔者最近在用多线程来计算中文文本的标点符号数目,遇到了以下问题:

  • 在Windows下,文本中汉字通常采用Unicode编码,这就导致需要随机(RandomAccessFile)读取文本时,产生乱码现象。
  • 多线程计算前(假设有2个线程),需要将文本内容尽量等分成2份,并输出到新的文件中,再进行计算。

总体思路:

  • 规定一次读取的字节数,再在存储和输出时转化成GBK编码

    • 由于RandomAccessFile可以随机定位读取起始点,当规定了一次读取的字节数,也就规定了读取结束点。
    • 按行读取,每一行的字节有对应的数组保存,转化成GBK后,写入输出文本。
  • 引入java.nio,在读取文件和转化编码时方便很多,笔者认为java.io也可以实现。
    • 关于NIO的详细教程可以参考:NIO系列教程
    • 本文引入java.nio.ByteBuffer,java.nio.channels.FileChannel,前者无需解释,后者为通道,相当于流。

具体代码实现如下:

package Yue.IO;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel; /**
* 将文本内容尽量分成n份,使n个线程处理对应的文本
*/
public class SplitFile {
int fileNum; //分离的文件数
File fileIn = new File("E:\\白夜行.txt");
int bufSize; SplitFile(int threadsNum) {
fileNum = threadsNum;
bufSize = (int) (fileIn.length() / fileNum); //一次读取的字节数
} FileChannel fileChaIn, fileChaOut;
ByteBuffer rBuffer, wBuffer; /*设置缓冲区,读文件时,最后一行往往不完整,需要将存在断点的那一行保存,与下一次读文本时的第一行合并*/
byte[] temp = new byte[0]; /**
* 按行具体读出每一个线程所要处理的文本内容
*
* @param NO Thread-NO
*/
public void readByLine(int NO) {
String enter = "\n";
byte[] lineByte; //保存每一行读取内容 /*确认读取范围*/
try {
RandomAccessFile raf = new RandomAccessFile(fileIn, "r");
raf.seek(NO * bufSize); //根据分离文本进程定位
fileChaIn = raf.getChannel();
rBuffer = ByteBuffer.allocate(bufSize);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} try {
if (fileChaIn.read(rBuffer) != -1) {
/*生成输出文件Part-No.txt*/
try {
fileChaOut = new RandomAccessFile("E:\\Part-" + NO + ".txt", "rws").getChannel();
wBuffer = ByteBuffer.allocateDirect(bufSize);
} catch (FileNotFoundException e) {
e.printStackTrace();
} /*根据一次读取,确定本次输出的字节长度*/
int rSize = rBuffer.position();
byte[] bs = new byte[rSize];
rBuffer.rewind();
rBuffer.get(bs);
rBuffer.clear(); int startNum = 0;
int LF = 10; //换行符
int CR = 13; //回车符
boolean hasLF = false; //是否有换行符
for (int i = 0; i < rSize; i++) {
if (bs[i] == LF) {
hasLF = true;
int tempNum = temp.length;
int lineNum = i - startNum;
lineByte = new byte[tempNum + lineNum]; //数组大小已经去掉换行符 /*把上一次读取保存在缓冲区的内容和本次读取的这一行的内容合并,保存到lineByte[]中*/
System.arraycopy(temp, 0, lineByte, 0, tempNum);
temp = new byte[0];
System.arraycopy(bs, startNum, lineByte, tempNum, lineNum); /*把该行内容转换成String类型,写入输出文件中*/
String line = new String(lineByte, 0, lineByte.length, "GBK");
writeByLine(line + enter); /*过滤回车和换行*/
if (i == rSize - 1 && bs[i + 1] == CR) {
startNum = i + 2;
} else {
startNum = i + 1;
}
}
} /*对每次读取的最后一行做特殊处理,将未读完整的当前行不输出,保存在缓冲区中,与下一次读取时合并*/
if (hasLF) {
temp = new byte[bs.length - startNum];
System.arraycopy(bs, startNum, temp, 0, temp.length);
} else {
/*兼容单次读取不足一行的情况*/
byte[] toTemp = new byte[bs.length + temp.length];
System.arraycopy(temp, 0, toTemp, 0, temp.length);
System.arraycopy(bs, 0, toTemp, temp.length, bs.length);
temp = toTemp;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileChaIn.close();
fileChaOut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} /**
* 写入输出文件
*
* @param line 已转换成String类型的当前行文本内容
*/
public void writeByLine(String line) {
try {
fileChaOut.write(wBuffer.wrap(line.getBytes("GBK")), fileChaOut.size());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Java.nio-随机读写汉字的更多相关文章

  1. java中随机生成汉字

    main方法中使用: //随机生成100个汉字 String ss=""; for(int i=0;i<100;i++){ ss+=getChinese(i); } Syst ...

  2. java nio 缓冲区读写数据(图形详解)

    Position 您可以回想一下,缓冲区实际上就是美化了的数组.在从通道读取时,您将所读取的数据放到底层的数组中. position 变量跟踪已经写了多少数据.更准确地说,它指定了下一个字节将放到数组 ...

  3. Java基础之读文件——使用通道随机读写文件(RandomReadWrite)

    控制台程序,使用通道随机读写primes_backup.bin文件. import static java.nio.file.StandardOpenOption.*; import java.nio ...

  4. Java知多少(72)文件的随机读写

    Java.io 包提供了 RandomAccessFile 类用于随机文件的创建和访问.使用这个类,可以跳转到文件的任意位置读写数据.程序可以在随机文件中插入数据,而不会破坏该文件的其他数据.此外,程 ...

  5. Java编程的逻辑 (60) - 随机读写文件及其应用 - 实现一个简单的KV数据库

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  6. 【JavaNIO的深入研究4】内存映射文件I/O,大文件读写操作,Java nio之MappedByteBuffer,高效文件/内存映射

    内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件.有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问.这种解决办法能大大简化修改文件的代码.fileC ...

  7. java大文件读写操作,java nio 之MappedByteBuffer,高效文件/内存映射

    java处理大文件,一般用BufferedReader,BufferedInputStream这类带缓冲的Io类,不过如果文件超大的话,更快的方式是采用MappedByteBuffer. Mapped ...

  8. java 随机读写访问流及seek方法

    package stream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOExceptio ...

  9. Java IO流之普通文件流和随机读写流区别

    普通文件流和随机读写流区别 普通文件流:http://blog.csdn.net/baidu_37107022/article/details/71056011 FileInputStream和Fil ...

随机推荐

  1. 用user-selection实现让页面上的内容不能被选中

    最开始发现这个功能是在陌小雨的博客中,然后自己百度发现用的是user-selection功能,之前网上有很多关于禁止右键,禁止复制,禁止粘 贴,禁止剪切等都弱爆了.这个功能正好使用到我的网站上啊,(你 ...

  2. Intellij IDEA debug模式下项目启动慢/无法启动的事件解决过程记录

    项目无法启动了 简单的介绍一下事件过程:周一的早上,收到前端同事抛过来的一个任务,说是一个接口无法正常返回数据,于是就让他把参数发过来,我想试着在本地重现一下并且将问题修复掉,这种情况肯定是要通过de ...

  3. win7开通共享步骤

    win7开通共享步骤 2017-10-09    11:12:09 个人原创博客,允许转载,转载请注明作者及出处,否则追究法律责任 1,开通来宾账户 2,为来宾账户创建一个空密码 右键我的电脑,管理, ...

  4. 解决python本地离线安装requests问题

    使用python36进行本地requests安装的时候,由于安装requests需要联网,导致安装失败,现象如下: 一开始以为,需要安装什么证书,其实只是需要一个python的证书库,(⊙﹏⊙)b 执 ...

  5. 边做边学入门微信小程序之仿豆瓣评分

    微信小程序由于适用性强.逻辑简要.开发迅速的特性,叠加具有海量活跃用户的腾讯公司背景,逐渐成为了轻量级单一功能应用场景的较佳承载方式,诸如电影购票.外卖点餐.移动商城.生活服务等场景服务提供商迅速切入 ...

  6. JavaScript -- 知识点汇总

    js语法 1. javascript数据类型 JavaScript拥有动态类型.这意味着相同的变量可用作不同的类型:有 字符串,数字, 布尔值, 对象, 数组,Undefined和Null 对象: v ...

  7. mysql数据库索引优化与实践(一)

    前言 mysql数据库是现在应用最广泛的数据库系统.与数据库打交道是每个Java程序员日常工作之一,索引优化是必备的技能之一. 为什么要了解索引 真实案例 案例一:大学有段时间学习爬虫,爬取了知乎30 ...

  8. 【highlight.js】页面代码高亮插件

    [highlight.js] 很多博客都支持页面插入各种语言的代码,而这些代码肯定是有高亮设置的.那么在我们自己的页面上如何进行代码高亮设置?有现成的这个highlight.js插件我们可以使用. h ...

  9. Matlab绘图基础——散点生成三角网(TIN)

    %例一:二维三角网TIN模型的生成 X=rand(10,2)*5; dt=DelaunayTri(X(:,1),X(:,2));       %生成三角网 triplot(dt);hold on;   ...

  10. Matlab绘图基础——其他三维图形(绘制填充的五角星)

    其他三维图形 %绘制魔方阵的三维条形图 subplot(2,2,1); bar3(magic(4));   %以三维杆图形式绘制曲线y=2sin(x) subplot(2,2,2); y=2*sin( ...