मैं दुर्भाग्यवश, दो प्रकार के वर्ण एन्कोडिंग वाली फ़ाइल से डेटा पढ़ रहा हूं।इनपुटस्ट्रीम रीडर बफरिंग समस्या
एक शीर्षलेख और शरीर है। हेडर हमेशा ASCII में होता है और उस चरित्र सेट को परिभाषित करता है जिसमें शरीर को एन्कोड किया जाता है।
हेडर निश्चित लंबाई नहीं है और इसकी सामग्री/लंबाई निर्धारित करने के लिए एक पार्सर के माध्यम से चलाया जाना चाहिए।
फ़ाइल भी काफी बड़ी हो सकती है इसलिए मुझे पूरी सामग्री को स्मृति में लाने से बचने की आवश्यकता है।
तो मैंने एक इनपुट इनपुट के साथ शुरू किया। मैं शुरुआत में एएससीआईआईआई के साथ एक इनपुटस्ट्रीम रीडर के साथ लपेटता हूं और हेडर को डीकोड करता हूं और शरीर के लिए चरित्र सेट निकालता हूं। सब अच्छा।
फिर मैं सही चरित्र सेट के साथ एक नया इनपुटस्ट्रीम रीडर बना देता हूं, इसे उसी इनपुटस्ट्रीम पर छोड़ देता हूं और शरीर को पढ़ने की कोशिश करना शुरू करता हूं।
दुर्भाग्यवश ऐसा प्रतीत होता है, जावाडोक यह पुष्टि करता है कि इनपुटस्ट्रीम रीडर effeciency उद्देश्यों के लिए आगे पढ़ने का विकल्प चुन सकता है। तो हेडर का पठन कुछ/सभी शरीर को चबाता है।
क्या किसी को इस मुद्दे के आसपास काम करने के लिए कोई सुझाव है? एक CharsetDecoder मैन्युअल रूप से और एक बाइट में एक बार में भोजन करना एक अच्छा विचार (संभवतः एक कस्टम रीडर कार्यान्वयन में लपेटा गया है?)
अग्रिम धन्यवाद।
संपादित करें: मेरा अंतिम समाधान एक इनपुटस्ट्रीम रीडर लिखना था जिसमें यह सुनिश्चित करने के लिए कोई बफरिंग नहीं है कि मैं शरीर के चबाने के बिना हेडर को पार्स कर सकता हूं। यद्यपि यह बहुत कुशल नहीं है, लेकिन मैं कच्चे इनपुटस्ट्रीम को BufferedInputStream के साथ लपेटता हूं, इसलिए यह कोई समस्या नहीं होगी।
// An InputStreamReader that only consumes as many bytes as is necessary
// It does not do any read-ahead.
public class InputStreamReaderUnbuffered extends Reader
{
private final CharsetDecoder charsetDecoder;
private final InputStream inputStream;
private final ByteBuffer byteBuffer = ByteBuffer.allocate(1);
public InputStreamReaderUnbuffered(InputStream inputStream, Charset charset)
{
this.inputStream = inputStream;
charsetDecoder = charset.newDecoder();
}
@Override
public int read() throws IOException
{
boolean middleOfReading = false;
while (true)
{
int b = inputStream.read();
if (b == -1)
{
if (middleOfReading)
throw new IOException("Unexpected end of stream, byte truncated");
return -1;
}
byteBuffer.clear();
byteBuffer.put((byte)b);
byteBuffer.flip();
CharBuffer charBuffer = charsetDecoder.decode(byteBuffer);
// although this is theoretically possible this would violate the unbuffered nature
// of this class so we throw an exception
if (charBuffer.length() > 1)
throw new IOException("Decoded multiple characters from one byte!");
if (charBuffer.length() == 1)
return charBuffer.get();
middleOfReading = true;
}
}
public int read(char[] cbuf, int off, int len) throws IOException
{
for (int i = 0; i < len; i++)
{
int ch = read();
if (ch == -1)
return i == 0 ? -1 : i;
cbuf[ i ] = (char)ch;
}
return len;
}
public void close() throws IOException
{
inputStream.close();
}
}
हो सकता है कि मैं गलत हूँ, लेकिन इस समय के बाद से मैंने सोचा था कि फ़ाइल एक ही समय में केवल एक ही एन्कोडिंग प्रकार हो सकता है। – Roman
@Roman: आप कुछ भी फाइलों के साथ कर सकते हैं; वे केवल बाइट्स के अनुक्रम हैं। तो आप बाइट्स का एक गुच्छा लिख सकते हैं जिसका अर्थ ASCII के रूप में किया जाना है, फिर यूटीएफ -16 के रूप में व्याख्या करने के लिए एक और अधिक बाइट्स लिखें, और यूटीएफ -32 के रूप में व्याख्या करने के लिए और भी बाइट्स लिखें। मैं यह नहीं कह रहा हूं कि यह एक अच्छा विचार है, हालांकि ओपी का उपयोग मामला निश्चित रूप से उचित है (आपके पास यह इंगित करने के लिए * कुछ * तरीका होना चाहिए कि फ़ाइल का एन्कोडिंग किस प्रकार उपयोग करता है)। –
@ माइक क्यू - इनपुटस्ट्रीम रीडर यूनबफर्ड का अच्छा विचार। मैं एक अलग उत्तर का सुझाव देता हूं - यह ध्यान देने योग्य है :) –