Java单词交替合并面试题

来源:
三产
最后修订:
2016年04月20日 00:00:00
 341

今天看到一道面试题,题目为:编写一个程序,将a.txt文件中的单词与b.txt文件中的单词进行交替合并到c.txt文件中 。a.txt文件中的单词用回车符分隔,b.txt文件中用回车或空格分开。 文章中给出的代码是

impor...

今天看到一道面试题,题目为:编写一个程序,将a.txt文件中的单词与b.txt文件中的单词进行交替合并到c.txt文件中 。a.txt文件中的单词用回车符分隔,b.txt文件中用回车或空格分开。 文章中给出的代码是

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;


public class TwoTxt {
    public static void main(String[] args) throws Exception {
        FileManager a = new FileManager("E:\\IdeaProjects\\面试\\src\\a.txt", new char[]{'\n'});
        FileManager b = new FileManager("E:\\IdeaProjects\\面试\\src\\b.txt", new char[]{'\n', ' '});
        FileWriter c = new FileWriter("E:\\IdeaProjects\\面试\\src\\c.txt");
        String aWord = null;
        String bWord = null;
        //交替写入
        while ((aWord = a.nextWord()) != null) {
            c.write(aWord + "\n");
            bWord = b.nextWord();
            if (bWord != null) {
                c.write(bWord + "\n");
            }
        }
        //确保b.txt写完
        while ((bWord = b.nextWord()) != null) {
            c.write(bWord + "\n");
        }
        c.close();
    }
}

class FileManager {
    String[] words = null;
    int pos = 0;

    /**
     * @param filename
     * @param seperators 单词间的分隔符
     * @throws Exception
     */
    public FileManager(String filename, char[] seperators) throws Exception {
        File f = new File(filename);
        FileReader reader = new FileReader(f);
        char[] buf = new char[(int) f.length()];
        int len = reader.read(buf);
        String result = new String(buf, 0, len);
        String regex = null;
        if (seperators.length > 1) {
            regex = "" + seperators[0] + "|" + seperators[1];
        } else {
            regex = "" + seperators[0];
        }
        words = result.split(regex);
    }

    public String nextWord() {
        if (pos == words.length) {
            return null;
        }
        return words[pos++];
    }
}

代码本身能够做到题目的要求,但是有几处考虑不足:

  1. 在FileManager类中,我们使用FileReader字符流打开了资源,而在程序最后并没有关闭该资源,这是十分危险的操作。

  2. 在使用FileReader对文件进行读取时,只是简单的读取了一次就把读取到的数据封装成了String字符串。如果我们要读取的文件较小,只有几KB,那没有问题。那么,当我们读取的文件很大,大到一次并不能读取完,这时就出问题了。

  3. (这处也许是我多虑了)我们都知道,Linux和windows下的文件在回车换行方面处理不同。“\r,\n”都有新起一行的效果,但在两种操作系统中处理方式不同,也就是说,在windows下当我们敲下回车键时,在新起的上一行的最后会自动添加“\r\n”,而Linux下只会添加“\n”。此时就体现出了操作系统的差异性。那么我们对待这两种操作系统要有不同的操作。同时,在我们向新文件即c.txt文件中写入时,如果使用的是c.write(aWord + “\n”);,那么在Windows下打开该文件,所有的单词应该显示成一行,而Linux操作系统下则会一个单词一个换行。

    对上述不足改进

  4. 添加对资源进行关闭的方法

 public void close() {
        if (fis != null) {  //fis是读取文件的字节流
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                fis = null;
            }
        }
    }
  1. 对读取文件内容进行改进
  /**从文件中读取数据*/
        byte[] a = new byte[fis.available()];
        int len = fis.read(a);
        int total = 0;
        //如果total小于字节数组的长度,说明文件没有读取完成  
        while (total < a.length) {
            total += len;
            //向字节数组中写入数据,起始偏移量是已读取数据长度, a.length - total表示剩余数据长度  
            len = fis.read(a, total, a.length - total);
        }

最终改进后代码

import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;

/**
 * 将a.txt文件中的单词与b.txt文件中的单词进行交替合并到c.txt文件中
 * a.txt文件中的单词用回车符分隔,b.txt文件中用回车或空格分开
 *
 * @author sanchan
 */
public class TwoTxt {

    public static void main(String[] args) throws Exception {
        /**获取当前操作系统的换行符*/
        String lineSeparator = System.getProperty("line.separator");
        /** 在不同的平台上,换行符可能是不同的,例如:

         Mac平台:\r
         Unix或Linux:\n
         Windows或Http:\r\n
         Unicode标准:\u2028

         所以当需要换行时,通常建议使用line.separator的系统属性:System.getProperty("line.separator")*/
        FileManager fma = new FileManager("a.txt", new String[]{"\n", "\r\n"});
        /**"\\s"表示空格*/
        FileManager fmb = new FileManager("b.txt", new String[]{"\n", "\r\n", "\\s"});
        //c.txt文件保存位置是类路径即bin目录下  
        FileWriter fw = new FileWriter(new File(ClassLoader.getSystemResource("").getFile(), "c.txt"));
        String aWord = null;
        String bWord = null;
        while ((aWord = fma.nextWord()) != null) {
            //添加“A:”是为了观察容易结果是按怎样的顺序写入文件的
            fw.write("A:" + aWord + lineSeparator);
            if ((bWord = fmb.nextWord()) != null) {
                fw.write("B:" + bWord + lineSeparator);
            }
        }
        while ((bWord = fmb.nextWord()) != null) {
            fw.write("B:" + bWord + lineSeparator);
        }
        fw.flush();
        fw.close();
        /**关闭文件字符流对a.txt和b.txt资源的连接*/
        fma.close();
        fmb.close();
    }

}

class FileManager {
    String[] words = null;
    int pos = 0;
    FileInputStream fis = null;

    public FileManager() {
    }

    public FileManager(String fileName, String[] seperators) throws Exception {
        /**获取当前项目的类路径*/
        URL classpath = FileManager.class.getClassLoader().getResource("");

        File file = new File(classpath.getFile(), fileName);
        fis = new FileInputStream(file);

        /**从文件中读取数据*/
        byte[] a = new byte[fis.available()];
        int len = fis.read(a);
        int total = 0;
        //如果total小于字节数组的长度,说明文件没有读取完成  
        while (total < a.length) {
            total += len;
            //向字节数组中写入数据,起始偏移量是已读取数据长度, a.length - total表示剩余数据长度
            len = fis.read(a, total, a.length - total);
        }
        StringBuffer regex = new StringBuffer();
        for (String seperator : seperators) {
            regex.append(seperator + "|");
        }
        regex.deleteCharAt(regex.length() - 1);
        words = new String(a).split(regex.toString());
    }

    public String nextWord() {
        if (pos >= words.length) {
            return null;
        }
        return words[pos++];
    }

    public void close() {
        if (fis != null) {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                fis = null;
            }
        }
    }
}

结果示例 从左到右文件名依次为: c.txt, b.txt, a.txt, 文件C.txt文件b.txt文件a.txt