项目经验,如需转载,请注明作者:Yuloran (t.cn/EGU6c76)

背景

项目开发需要手动合入几十种语言的翻译到 string.xml 中,这是一件非常痛苦的事情:Copy、Paste,Copy、Paste,Copy、Paste... 人都快疯了!被逼无奈写了个自动替换翻译的工具,原理很简单:解析 Excel中的翻译,替换到 Xml 中。Excel 解析用 jxl.jar,Xml 解析与修改用 DOM,一顿操作,一天就写完了!正高兴呢,赶紧使用 git diff 查看修改对比,一看坏事了:“坑爹呢!这特么根本不能用好嘛!原文件的每一行都被识别成了新行(因为换行符变了),这代码还怎么审核?鬼知道你改了什么!” 所以,本文记录如何使用 Java 识别与转换文件换行符。

文件换行符分类

Intellij>File>Line Separators:

查看 ASCII 码表:

\r(CR (carriage return)):十六进制为 0x0D

\n(LF (NL line feed, new line)):十六进制为 0x0A

Windows 换行符:\r\n,回车键+换行键;

Linux 换行符:\n,换行键;

Mac 换行符:\r,回车键。

没有换行符:文件的最后一行可以没有换行符

识别文件符

按行读取文件,然后再分别读出接下来的两个字节,判断其 int 值:

package com.yuloran.util;

import java.io.EOFException;

import java.io.File;

import java.io.IOException;

import java.io.RandomAccessFile;

public final class LineSeparatorHelper{

public enum LINE_SEPARATOR {

WINDOWS, LINUX, MAC, UNKNOWN

}

private LineSeparatorHelper(){

}

public static LINE_SEPARATOR getLineSeparator(File f) throws IllegalArgumentException{

if (f == null || !f.isFile() || !f.exists()) {

throw new IllegalArgumentException("file must exists!");

}

RandomAccessFile raf = null;

try {

raf = new RandomAccessFile(f, "r");

String line = raf.readLine();

if (line == null) {

return LINE_SEPARATOR.UNKNOWN;

}

// 必须执行这一步,因为 RandomAccessFile 的 readLine() 会自动忽略并跳过换行符,所以需要先回退文件指针位置

// "ISO-8859-1" 为 RandomAccessFile 使用的字符集,此处必须指定,否则中文 length 获取不对

raf.seek(line.getBytes("ISO-8859-1").length);

byte nextByte = raf.readByte();

if (nextByte == 0x0A) {

return LINE_SEPARATOR.LINUX;

}

if (nextByte != 0x0D) {

return LINE_SEPARATOR.UNKNOWN;

}

try {

nextByte = raf.readByte();

if (nextByte == 0x0A) {

return LINE_SEPARATOR.WINDOWS;

}

return LINE_SEPARATOR.MAC;

} catch (EOFException e) {

return LINE_SEPARATOR.MAC;

}

} catch (IOException e) {

e.printStackTrace();

} finally {

if (raf != null) {

try {

raf.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

return LINE_SEPARATOR.UNKNOWN;

}

}

复制代码

使用 Intellij 创建一个 Java 工程,编写一个控制台应用,测试以上代码:

package com.yuloran;

import com.yuloran.util.LineSeparatorHelper;

import java.io.File;

public class Main{

public static void main(String[] args){

File f = new File("test.txt");

System.out.println("line separator: " + LineSeparatorHelper.getLineSeparator(f).name());

}

}

复制代码

test.txt 的换行符通过 File>Line Separators 进行切换,换行符符号可用 Notepad 查看,比如Windows 换行符为:

Notepad 显示所有符号方法:

测试结果:

转换文件换行符

读出新文件换行符,若与原文件换行符不一致,则新建一临时文件,逐行写入原文件内容,并在行尾写入原文件换行符,然后删除原文件,重命名临时文件:

// 此处省略 LineSeparatorHelper 类其他代码...

@SuppressWarnings("ResultOfMethodCallIgnored")

public static boolean convert(LINE_SEPARATOR oldLs, File f, String charset){

if (oldLs == null || oldLs == LINE_SEPARATOR.UNKNOWN) {

return false;

}

if (f == null || !f.isFile() || !f.exists()) {

return false;

}

if (charset == null || charset.isEmpty()) {

charset = "UTF-8";

}

LINE_SEPARATOR newLs = getLineSeparator(f);

if (newLs == oldLs) {

return false;

}

File temp = new File(f.getParent(), "temp.txt");

if (temp.exists()) {

temp.delete();

}

BufferedReader br = null;

BufferedWriter bw = null;

try {

br = new BufferedReader(new InputStreamReader(new FileInputStream(f), charset));

bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(temp), charset));

String line;

int lineNumber = 0;

while ((line = br.readLine()) != null) {

if (lineNumber != 0) {

switch (oldLs) {

case WINDOWS:

bw.append('\r').append('\n');

break;

case LINUX:

bw.append('\n');

break;

case MAC:

bw.append('\r');

break;

default:

}

}

bw.write(line);

++lineNumber;

}

return true;

} catch (IOException e) {

e.printStackTrace();

} finally {

try {

if (br != null) {

br.close();

}

if (bw != null) {

bw.close();

}

} catch (IOException e) {

e.printStackTrace();

}

f.delete();

temp.renameTo(f);

}

return false;

}

复制代码

测试代码:

package com.yuloran;

import com.yuloran.util.LineSeparatorHelper;

import java.io.File;

public class Main{

public static void main(String[] args){

File f = new File("test.txt");

System.out.println("original line separator: " + LineSeparatorHelper.getLineSeparator(f).name());

LineSeparatorHelper.convert(LineSeparatorHelper.LINE_SEPARATOR.WINDOWS, f, "UTF-8");

System.out.println("new line separator: " + LineSeparatorHelper.getLineSeparator(f).name());

}

}

复制代码

测试结果:

总结

RandomAccessFile 以 "ISO-8859-1" 编码方式读取一行,获取字节数时,须指定该编码方式

RandomAccessFile 读取一行后,文件指针指向下一行开头,跳过了换行符所占的字节位置,读取换行符时须回退文件指针位置

没有字节可读时,调用 readByte() 会抛出 EOFException:public final byte readByte() throws IOException{

int ch = this.read();

if (ch < 0)

throw new EOFException();

return (byte)(ch);

}

复制代码

重命名文件、删除文件须在 IO 流关闭后执行

java 处理换行符_Java 文件换行符识别与转换相关推荐

  1. linux文件描述符泄漏,文件描述符(fd)泄漏排查一篇就够了

    生产多次遇到文件描述符(fd)泄露相关的问题, 文件描述符泄漏一般引起 的现象是文件句柄数(封面图)/tcp alloc(上图)增长.文章分为两部分介绍文件描述符相关内容,第一部分介绍文件描述基础知识 ...

  2. java i o中文版_Java文件I/O的三种方法

    摘要:之前在面试中被问到过两次Java中文件读入输出怎么写,当时只记得一个大概,没有办法很清晰的说出一个条理,今天特地看出总结了一下这方面的内容,想要写出来给大家分享.首先文件读入输出流常用有三种:F ...

  3. java输入输出换行程序_java文件输出换行问题。

    我想把程序处理的数据输出到文件中,而且是一行一个数据,比如:张三男十岁但是我在输出流中用\n不行,用\r\n也不行(文本文档),但是用\n输入到word文档里就可以实现换行.但是我又想... 我想把程 ...

  4. java final修饰符_java final修饰符详解,final修饰方法

    之前给大家讲过java final修饰符final修饰变量方面的知识,那么下面要继续给大家讲到的就是final修饰方法方面的知识,一起来了解一下吧. final修饰的方法不能被重写,假如因为一些原因, ...

  5. java的final修饰_java final 修饰符详解

    final修饰符究竟有什么作用,我们该如何使用,对我们的应用开发又能够起到什么作用,有java基础的肯定是不难说出final的几个用法, 1.被final修饰的变量在首次被初始化之后是不能够再次被赋值 ...

  6. java访问修饰符_Java访问修饰符

    java访问修饰符 Java access modifiers are used to provide access control in java. Java provides access con ...

  7. java 连接 sftp失败_java – 文件上传到SFTP失败(Apache VFS)

    我有一个SFTP问题( Windows WinSSHD).我尝试用 Apache Commons VFS在一个文件夹中写一个文件.在本地SFTP上我没有上传的问题,但在第二个SFTP上我总是得到以下错 ...

  8. java复制和上传_java文件上传复制等功能

    package com.sitech.message.controller.task; import java.io.File;//引入类 import java.io.FileInputStream ...

  9. java上传下载_Java文件上传与文件下载实现方法详解

    本文实例讲述了Java文件上传与文件下载实现方法.分享给大家供大家参考,具体如下: Java文件上传 数据上传是客户端向服务器端上传数据,客户端向服务器发送的所有请求都属于数据上传.文件上传是数据上传 ...

最新文章

  1. 安装 Enthought Tool Suite 时遇到的问题
  2. 计算机网络第四章-网络层复习笔记
  3. FOI冬令营 Day 3
  4. form表单多文件上传
  5. IBATIS的优缺点
  6. jQuery验证框架教程
  7. 如何下载谷歌地图高程数据
  8. CImage不失真缩放显示图片
  9. 游戏测试-笔试/面试(一)
  10. Miracle2.1 列表页面显示附件链接
  11. ssm框架访问数据库一直在转圈(请求)
  12. JAVA菜鸟驿站快递分发系统计算机毕业设计Mybatis+系统+数据库+调试部署
  13. 日志服务与日志分析工具
  14. rpm 安装MySQL8
  15. python多光谱遥感数据处理、图像分类、定量评估及机器学习方法
  16. 电子信箱怎么样注册?邮箱格式怎么写?
  17. 文件传输助手——自同步、使用方法
  18. 索尼IMX219图像传感器
  19. 应届生毕业就失业?这该怎么办
  20. eas 税率修改_关于调整增值税税率的通知

热门文章

  1. 2017研究生乒乓球比赛记录
  2. MCSManager 面板(MCSM面板)
  3. ffmpeg源码优化之推流发送篇
  4. 如何把sql文件导入到phpMyadmin数据库
  5. 开普勒架构和麦克斯韦架构是什么?有什么区别?
  6. mysql中怎么分页查询_mysql怎样实现分页查询
  7. JavaWeb常用工具/插件合集——validation和iCheck
  8. Doris系列16-物化视图
  9. oracle create database
  10. 推荐一波2018年让人惊喜的手机小众APP