UTF-8 byte [] ถึง String


243

สมมุติว่าฉันเพิ่งใช้ a BufferedInputStreamเพื่ออ่านไบต์ของไฟล์ข้อความที่เข้ารหัส UTF-8 ลงในอาร์เรย์ไบต์ ฉันรู้ว่าฉันสามารถใช้รูทีนต่อไปนี้เพื่อแปลงไบต์เป็นสตริง แต่มีวิธีที่มีประสิทธิภาพ / ชาญฉลาดกว่าในการทำสิ่งนี้มากกว่าแค่วนซ้ำผ่านไบต์และแปลงแต่ละรายการหรือไม่

public String openFileToString(byte[] _bytes)
{
    String file_string = "";

    for(int i = 0; i < _bytes.length; i++)
    {
        file_string += (char)_bytes[i];
    }

    return file_string;    
}

17
ทำไมคุณไม่ทำเช่นนี้ String fileString = new String(_bytes,"UTF-8");?
CoolBeans

1
อีกวิธีหนึ่งคือคุณสามารถใช้ BufferedReader เพื่ออ่านลงในอาร์เรย์ char
Andy Thomas


@CoolBeans ฉันทำได้ถ้าฉันรู้ว่าทำอย่างนั้น;) ขอบคุณ
skeryl

ขึ้นอยู่กับขนาดไฟล์ฉันไม่แน่ใจว่าการโหลดทั้งหมดbyte[]ในหน่วยความจำและการแปลงผ่านnew String(_bytes,"UTF-8")(หรือแม้กระทั่งโดยชิ้นที่มี+=สตริง) มีประสิทธิภาพมากที่สุด Chaining InputStreams and Readers อาจทำงานได้ดีขึ้นโดยเฉพาะในไฟล์ขนาดใหญ่
บรูโน่

คำตอบ:


498

ดู Constructor ของString

String str = new String(bytes, StandardCharsets.UTF_8);

และถ้าคุณรู้สึกขี้เกียจคุณสามารถใช้ห้องสมุดApache Commons IOเพื่อแปลง InputStream เป็น String โดยตรง:

String str = IOUtils.toString(inputStream, StandardCharsets.UTF_8);

13
หรือCharsetsของGuava.UTF_8ถ้าคุณอยู่บน JDK ที่เก่ากว่า 1.7
ปิด

6
ใช้ Charsets.UTF_8 ของ Guava หากคุณใช้ Android API ต่ำกว่า 19 ด้วย
Ben Clayton

และถ้าเครื่องหมายถูกบอกว่า: "การเริ่มต้นผิดกฎหมาย: การสร้างอินสแตนซ์ของ java.lang.String ควรหลีกเลี่ยง" แล้วอะไรล่ะ
Attila Neparáczki

1
คุณสามารถมองเห็นในที่นี่java.nio.charset.Charset.availableCharsets()map StandardCharsetsชุดอักขระทั้งหมดที่ไม่ได้เป็นเพียงชุดอักขระในที่ และถ้าคุณต้องการใช้ชุดอักขระอื่น ๆ และยังต้องการป้องกันตัวสร้างสตริงจากการขว้างปาUnsupportedEncodingExceptionคุณอาจใช้java.nio.charset.Charset.forName()
nyxz

2
IOUtils.toString (inputStream, StandardCharsets.UTF_8) เลิกใช้แล้ว
Aung Myat Hein

41

คลาส Java String มี built-in-constructor สำหรับการแปลงอาร์เรย์ไบต์เป็นสตริง

byte[] byteArray = new byte[] {87, 79, 87, 46, 46, 46};

String value = new String(byteArray, "UTF-8");

9

ในการแปลงข้อมูล utf-8 คุณไม่สามารถถือว่าการติดต่อ 1-1 ระหว่างไบต์และอักขระได้ ลองสิ่งนี้:

String file_string = new String(bytes, "UTF-8");

(Bah. ฉันเห็นว่าฉันกำลังจะกดปุ่มโพสต์คำตอบของคุณช้าลง)

หากต้องการอ่านไฟล์ทั้งหมดในรูปของ String ให้ทำดังนี้:

public String openFileToString(String fileName) throws IOException
{
    InputStream is = new BufferedInputStream(new FileInputStream(fileName));

    try {
        InputStreamReader rdr = new InputStreamReader(is, "UTF-8");
        StringBuilder contents = new StringBuilder();
        char[] buff = new char[4096];
        int len = rdr.read(buff);
        while (len >= 0) {
            contents.append(buff, 0, len);
        }
        return buff.toString();
    } finally {
        try {
            is.close();
        } catch (Exception e) {
            // log error in closing the file
        }
    }
}

4

คุณสามารถใช้ตัวString(byte[] bytes) สร้างสำหรับสิ่งนั้น ดูลิงค์นี้สำหรับรายละเอียด แก้ไขคุณต้องพิจารณาชุดอักขระเริ่มต้นของ plateform ตาม java doc:

สร้าง String ใหม่โดยการถอดรหัสอาร์เรย์ของไบต์ที่ระบุโดยใช้ชุดอักขระเริ่มต้นของแพลตฟอร์ม ความยาวของสตริงใหม่เป็นฟังก์ชันของชุดอักขระและด้วยเหตุนี้อาจไม่เท่ากับความยาวของอาร์เรย์ไบต์ พฤติกรรมของนวกรรมิกนี้เมื่อไบต์ที่กำหนดไม่ถูกต้องในชุดอักขระเริ่มต้นจะไม่ได้รับการระบุ คลาส CharsetDecoder ควรใช้เมื่อต้องการการควบคุมกระบวนการถอดรหัสเพิ่มเติม


1
และหากไบต์ของคุณไม่อยู่ในชุดอักขระเริ่มต้นของแพลตฟอร์มคุณสามารถใช้เวอร์ชันที่มีCharsetอาร์กิวเมนต์ที่สองเพื่อให้แน่ใจว่าการแปลงนั้นถูกต้อง
Mike Daniels

1
@ MikeDaniels แน่นอนฉันไม่ต้องการรวมรายละเอียดทั้งหมด เพิ่งแก้ไขคำตอบของฉัน
GETah

2

คุณสามารถใช้วิธีการที่อธิบายไว้ในคำถามนี้ (โดยเฉพาะอย่างยิ่งเมื่อคุณเริ่มด้วย InputStream): อ่าน / แปลง InputStream เป็นสตริง

โดยเฉพาะอย่างยิ่งถ้าคุณไม่ต้องการพึ่งพาห้องสมุดภายนอกคุณสามารถลองคำตอบนี้ซึ่งอ่านInputStreamผ่านการInputStreamReaderเป็นบัฟเฟอร์และผนวกเข้ากับchar[]StringBuilder


2

รู้ว่าคุณจะจัดการกับอาร์เรย์ไบต์ UTF-8 คุณแน่นอนจะต้องการที่จะใช้ตัวสร้าง String ที่ยอมรับชื่อ มิฉะนั้นคุณอาจปล่อยให้ตัวเองเปิดช่องโหว่ความปลอดภัยตามการเข้ารหัส charset โปรดทราบว่ามันจะพ่นUnsupportedEncodingExceptionซึ่งคุณจะต้องจัดการ บางสิ่งเช่นนี้

public String openFileToString(String fileName) {
    String file_string;
    try {
        file_string = new String(_bytes, "UTF-8");
    } catch (UnsupportedEncodingException e) {
        // this should never happen because "UTF-8" is hard-coded.
        throw new IllegalStateException(e);
    }
    return file_string;
}

2

นี่คือฟังก์ชั่นที่เรียบง่ายที่จะอ่านเป็นไบต์และสร้างสตริง ถือว่าคุณอาจรู้อยู่แล้วว่าการเข้ารหัสไฟล์อยู่ใน (และค่าเริ่มต้น)

static final int BUFF_SIZE = 2048;
static final String DEFAULT_ENCODING = "utf-8";

public static String readFileToString(String filePath, String encoding) throws IOException {

    if (encoding == null || encoding.length() == 0)
        encoding = DEFAULT_ENCODING;

    StringBuffer content = new StringBuffer();

    FileInputStream fis = new FileInputStream(new File(filePath));
    byte[] buffer = new byte[BUFF_SIZE];

    int bytesRead = 0;
    while ((bytesRead = fis.read(buffer)) != -1)
        content.append(new String(buffer, 0, bytesRead, encoding));

    fis.close();        
    return content.toString();
}

แก้ไขโค้ดเพื่อให้ค่าเริ่มต้นเป็น utf-8 เพื่อให้ตรงกับคำถามของ OP
กอตต์


0

สิ่งนี้ยังเกี่ยวข้องกับการวนซ้ำ แต่มันดีกว่าการต่อสตริงเนื่องจากมันมีราคาแพงมาก

public String openFileToString(String fileName)
{
    StringBuilder s = new StringBuilder(_bytes.length);

    for(int i = 0; i < _bytes.length; i++)
    {
        s.append((char)_bytes[i]);
    }

    return s.toString();    
}

8
ท่านที่รักของฉัน String str = new String(byte[])จะทำอะไรได้ดี
zengr

3
สิ่งนี้ช่วยปรับปรุงประสิทธิภาพ แต่มันไม่ได้ถอดรหัสข้อมูล utf8 อย่างถูกต้อง
Ted Hopp

0

ทำไมไม่ได้รับสิ่งที่คุณกำลังมองหาจากการเดินทางและอ่านสตริงจากไฟล์แทนที่จะเป็นอาร์เรย์ไบต์? สิ่งที่ต้องการ:

BufferedReader in = new BufferedReader(new InputStreamReader( new FileInputStream( "foo.txt"), Charset.forName( "UTF-8"));

จากนั้นอ่านบรรทัดจากในจนกว่าจะเสร็จ


บางครั้งมันมีประโยชน์ในการรักษาตัวคั่นบรรทัดเดิม OP อาจต้องการสิ่งนั้น
บรูโน่

0

ฉันใช้วิธีนี้

String strIn = new String(_bytes, 0, numBytes);


1
นี่ไม่ได้ระบุชุดอักขระดังนั้นคุณจะได้รับชุดอักขระเริ่มต้นของแพลตฟอร์มซึ่งอาจไม่ใช่ UTF-8
greg-449
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.