Java Strings打破文件操作

时间:2012-03-05 15:37:53

标签: java string encryption encoding file-io

我的程序出现故障,导致问号(\ u003f)在加密时出现在字符串的第六个(index = 5)插槽中。通常,这在解密时会反转。但是,如果我先将字符串保存到文件中,则不会反转。我已经确定当我将包含Unicode字符的字符串保存到文件时,我将无法确定文件的正确长度。我已设法在以下功能中重现故障......

public static void testFileIO(String[] args)
{
    System.out.println("TESTING FILE IO FUNCTIONS...");
    try
    {
        String filename = "test.txt";
        String testString = "UB\u4781ERBLAH\u037f\u8746";
        System.out.println("Output: " + testString);
        FileWriter fw = new FileWriter(filename);
        fw.write(testString);
        fw.close();

        FileReader fr = new FileReader(filename);
        int length;
        for(length = 0; fr.read() != -1; length++);
        if(length != testString.length())
            System.out.println("Failure on file length measurement.");
        fr.close();

        fr = new FileReader(filename);
        char[] buffer = new char[length];
        fr.read(buffer);
        String result = new String(buffer);
        fr.close();
        System.out.println("Input: " + result);
        if(result.equals(testString)) System.out.println("SUCCESS!");
        else System.out.println("FAILURE.");
    }
    catch (Throwable e)
    {
        e.printStackTrace();
        System.out.println("FAILURE.");
        return;
    }
}

作为补充说明,还会发现文件长度测量失败。

这是我用来加密和解密字符串的Crypto类......

abstract public class Crypto
{  
    /**
     * Encrypt the plaintext with a bitwise xor cipher
     * @param plainText The plaintext to encrypt
     * @param password The key for the bitwise xor cipher
     * @return Ciphertext yielded by given plaintext and password
     */
    public static String encrypt(String plainText, String key)
    {
        char[] data = plainText.toCharArray();
        Random rand = new Random();
        rand.setSeed(key.hashCode());

        char[] pass = new char[data.length];
        for(int i = 0; i < pass.length; i++)
        {
            pass[i] = (char)rand.nextInt();
        }

        for(int i = 0; i < data.length; i++)
        {
            data[i] ^= pass[i % pass.length];
        }
        return new String(data);
    }

    /**
     * Decrypt an encrypted message using the same key as for encryption
     * @param cipherText The cipherText message to be deciphered
     * @param password The seed for the random generator to get the right keys
     * @return The plaintext message corresponding to 'cipherText'
     */
    public static String decrypt(String cipherText, String key)
    {
        char[] data = cipherText.toCharArray();
        Random rand = new Random();
        rand.setSeed(key.hashCode());

        char[] pass = new char[data.length];// = key.getBytes("ASCII");
        for(int i = 0; i < pass.length; i++)
        {
            pass[i] = (char)rand.nextInt();
        }

        for(int i = 0; i < data.length; i++)
        {
            data[i] ^= pass[i % pass.length];
        }
        return new String(data);
    }
}

1 个答案:

答案 0 :(得分:3)

代码是正确的,但几乎从不起作用 - 根据经验,避免FileReaderFileWriter并使用InputStreamReaderOutputStreamWriter建立自己的读者/作者允许您指定要使用的编码(以及在编写8位数据时如何保护16位Unicode字符)。

我使用辅助类是因为我一直需要它:

private static final String FILE = "file";
private static final String CHARSET = "charset";

public static BufferedReader createReader( File file, Encoding charset ) throws IOException {
    JavaUtils.notNull( FILE, file );
    JavaUtils.notNull( CHARSET, charset );

    FileInputStream stream = null;
    try {
        stream = new FileInputStream( file );
        return createReader( stream, charset );
    } catch( IOException e ) {
        IOUtils.closeQuietly( stream );
        throw e;
    } catch( RuntimeException e ) {
        IOUtils.closeQuietly( stream );
        throw e;
    }
}

public static BufferedReader createReader( InputStream stream, Encoding charset ) throws IOException {
    JavaUtils.notNull( "stream", stream );
    JavaUtils.notNull( "charset", charset );

    try {
        return new BufferedReader( new InputStreamReader( stream, charset.encoding() ) );
    } catch( UnsupportedEncodingException e ) {
        IOUtils.closeQuietly( stream );
        throw new UnknownEncodingException( charset, e );
    } catch( RuntimeException e ) {
        IOUtils.closeQuietly( stream );
        throw e;
    }
}

public static BufferedWriter createWriter( File file, Encoding charset ) throws IOException {
    JavaUtils.notNull( FILE, file );
    JavaUtils.notNull( CHARSET, charset );

    FileOutputStream stream = null;
    try {
        stream = new FileOutputStream( file );
        return new BufferedWriter( new OutputStreamWriter( stream, charset.encoding() ) );
    } catch( UnsupportedEncodingException e ) {
        IOUtils.closeQuietly( stream );
        throw new UnknownEncodingException( charset, e );
    } catch( IOException e ) {
        IOUtils.closeQuietly( stream );
        throw e;
    } catch( RuntimeException e ) {
        IOUtils.closeQuietly( stream );
        throw e;
    }
}

类型Encoding是我使用一个或多个enum s实现的接口:

public interface Encoding {
    String encoding();
    Charset charset();
}