วิธีการแปลง Reader เป็น InputStream และ Writer เป็น OutputStream


89

มีวิธีง่ายๆในการหลีกเลี่ยงการจัดการกับปัญหาการเข้ารหัสข้อความหรือไม่?

คำตอบ:


46

คุณไม่สามารถหลีกเลี่ยงการจัดการกับปัญหาการเข้ารหัสข้อความได้ แต่มีวิธีแก้ไขที่มีอยู่ใน Apache Commons:

คุณเพียงแค่ต้องเลือกการเข้ารหัสที่คุณต้องการ


7
FYI: โค้ด ReaderInputStream มีข้อผิดพลาดในการอ่านไบต์ (จะใช้ไม่ได้กับการเข้ารหัสทั้งหมด) หลักฐาน: ผิดกฎหมายargumentexception.blogspot.com/2009/05/…มีข้อผิดพลาดที่เปิดอยู่: issue.apache.org/bugzilla/show_bug.cgi?id=40455
McDowell

1
คุณสามารถค้นหาคลาสได้ในไลบรารี commons-io ของ Apache: commons.apache.org/proper/commons-io
AlikElzin-kilaka

@McDowell ข้อผิดพลาดที่คุณกล่าวถึงอยู่ในการใช้งานของ Apache Ant ไม่ใช่ในคอมมอนส์ - ไอโอดังนั้นจึงไม่เกี่ยวข้องกับคำตอบนี้
โรมัน

94

หากคุณกำลังเริ่มต้นด้วย String คุณสามารถทำสิ่งต่อไปนี้:

new ByteArrayInputStream(inputString.getBytes("UTF-8"))

7
ReaderInputStreamการนำไปใช้งานที่ดีจะต้องใช้หน่วยความจำน้อยลง - ไม่จำเป็นต้องเก็บไบต์ทั้งหมดในอาร์เรย์พร้อมกัน
Piotr Findeisen

3
ฉันชอบโซลูชันนี้เพราะใช้งานได้เมื่อคุณต้องการหน่วยรหัสทดสอบที่ยอมรับอินพุตบน (เช่น) อินพุตมาตรฐาน
Kedar Mhaswade

43

ผู้อ่านเกี่ยวข้องกับอักขระและข้อตกลง InputStream กับไบต์ การเข้ารหัสจะระบุวิธีที่คุณต้องการแทนอักขระของคุณเป็นไบต์ดังนั้นคุณจึงไม่สามารถเพิกเฉยต่อปัญหาได้ สำหรับการหลีกเลี่ยงปัญหาความคิดเห็นของฉันคือเลือกชุดอักขระหนึ่งชุด (เช่น "UTF-8") และติดไปด้วย

เกี่ยวกับวิธีการทำจริงตามที่ได้รับการชี้ออกมา " ชื่อที่ชัดเจนสำหรับการเรียนเหล่านี้เป็นReaderInputStreamและWriterOutputStream . " แปลกใจ " เหล่านี้จะไม่รวมอยู่ใน Java ห้องสมุด " แม้ว่าการเรียน 'ตรงข้าม' InputStreamReaderและOutputStreamWriter มีรวม

ดังนั้นผู้คนจำนวนมากได้มากับการใช้งานของตัวเองรวมทั้งApache Commons IO คุณอาจรวมไลบรารี commons-io ไว้ในโปรเจ็กต์ของคุณหรือแม้กระทั่งคัดลอกส่วนหนึ่งของซอร์สโค้ด (ซึ่งดาวน์โหลดได้ที่นี่ ) ทั้งนี้ขึ้นอยู่กับปัญหาการให้สิทธิ์การใช้งาน

ดังที่คุณเห็นเอกสารของทั้งสองคลาสระบุว่า "การเข้ารหัสชุดอักขระทั้งหมดที่ JRE รองรับได้รับการจัดการอย่างถูกต้อง"

หมายเหตุความคิดเห็นเกี่ยวกับหนึ่งในคำตอบอื่น ๆ ที่นี่กล่าวถึงข้อบกพร่องนี้ แต่มีผลกับคลาสApache Ant ReaderInputStream ( ที่นี่ ) ไม่ใช่คลาสApache Commons IO ReaderInputStream


19

โปรดทราบว่าหากคุณเริ่มต้นด้วย String คุณสามารถข้ามการสร้าง StringReader และสร้าง InputStream ได้ในขั้นตอนเดียวโดยใช้ org.apache.commons.io.IOUtils จากCommons IOดังนี้:

InputStream myInputStream = IOUtils.toInputStream(reportContents, "UTF-8");

แน่นอนว่าคุณยังคงต้องคิดถึงการเข้ารหัสข้อความ แต่อย่างน้อยการแปลงก็เกิดขึ้นในขั้นตอนเดียว


4
วิธีนี้ใช้โดยทั่วไปnew ByteArrayInputStream(report.toString().getBytes("utf-8"))ซึ่งเกี่ยวข้องกับการจัดสรรสำเนารายงานเพิ่มเติมสองชุดในหน่วยความจำ ถ้ารายงานมีจำนวนมากก็แย่ ดูคำตอบของฉัน
Oliv

8

ใช้:

new CharSequenceInputStream(html, StandardCharsets.UTF_8);

วิธีนี้ไม่จำเป็นต้องมีการแปลงล่วงหน้าเป็นStringแล้วเป็นbyte[]ซึ่งจะจัดสรรหน่วยความจำฮีปมากขึ้นในกรณีที่รายงานมีขนาดใหญ่ มันแปลงเป็นไบต์ได้ทันทีเมื่ออ่านสตรีมจาก StringBuffer

ใช้CharSequenceInputStreamจากโครงการ Apache Commons IO



5

ชื่อที่ชัดเจนสำหรับคลาสเหล่านี้ ได้แก่ ReaderInputStream และ WriterOutputStream น่าเสียดายที่สิ่งเหล่านี้ไม่รวมอยู่ในไลบรารี Java อย่างไรก็ตาม Google เป็นเพื่อนของคุณ

ฉันไม่แน่ใจว่ามันจะช่วยแก้ปัญหาการเข้ารหัสข้อความทั้งหมด

มี RFEแต่ปิดอยู่จะไม่แก้ไข


1
bugs.openjdk.java.net/browse/JDK-4103785มีความคิดเห็น "เรามี API สาธารณะสำหรับการเข้ารหัสชุดอักขระ ... ไม่มีเหตุผลที่น่าสนใจในการเพิ่มคลาสเหล่านี้" - ดังนั้นจะทำอย่างไรใน Java 7 โดยไม่ต้องเพิ่มเติม ห้องสมุดสิบสองปีตามท้องถนน?
Piotr Findeisen

5

คุณไม่สามารถหลีกเลี่ยงปัญหาการเข้ารหัสข้อความได้ แต่Apache commons-ioมี

โปรดทราบว่านี่คือไลบรารีที่อ้างถึงในคำตอบของ Peter ของ koders.com เพียงแค่ลิงก์ไปยังไลบรารีแทนซอร์สโค้ด


4

คุณกำลังพยายามเขียนเนื้อหาของ a ReaderถึงOutputStreamหรือไม่? ถ้าเป็นเช่นนั้นคุณจะมีเวลาได้ง่ายขึ้นการตัดOutputStreamในOutputStreamWriterและเขียนchars จากReaderไปWriterแทนการพยายามแปลงผู้อ่านไปยังInputStream:

final Writer writer = new BufferedWriter(new OutputStreamWriter( urlConnection.getOutputStream(), "UTF-8" ) );
int charsRead;
char[] cbuf = new char[1024];
while ((charsRead = data.read(cbuf)) != -1) {
    writer.write(cbuf, 0, charsRead);
}
writer.flush();
// don't forget to close the writer in a finally {} block

1

คำเตือนเมื่อใช้ WriterOutputStream - มันไม่ได้จัดการกับการเขียนข้อมูลไบนารีไปยังไฟล์อย่างถูกต้องเสมอไป / เหมือนกับสตรีมเอาต์พุตทั่วไป ฉันมีปัญหากับเรื่องนี้ซึ่งต้องใช้เวลาสักพักในการติดตาม

หากทำได้ฉันขอแนะนำให้ใช้เอาต์พุตสตรีมเป็นฐานของคุณและหากคุณต้องการเขียนสตริงให้ใช้ตัวตัด OUtputStreamWriter รอบ ๆ สตรีมเพื่อทำ การแปลงข้อความเป็นไบต์มีความน่าเชื่อถือมากกว่าวิธีอื่น ๆ ซึ่งเป็นไปได้ว่าทำไม WriterOutputStream ไม่ได้เป็นส่วนหนึ่งของไลบรารี Java มาตรฐาน



-1

สำหรับการอ่านสตริงในสตรีมโดยใช้สิ่งที่จาวาจัดหา

InputStream s = new BufferedInputStream( new ReaderInputStream( new StringReader("a string")));

6
ReaderInputStream อยู่ใน Apache Commons IO
Will Beason
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.