سؤال

هل هناك طريقة لقراءة ByteBuffer مع BufferedReader دون الحاجة إلى تحويلها إلى سلسلة أولا؟ أريد أن أقرأ من خلال ByteBuffer كبيرة إلى حد ما أسطر من النص ولأسباب تتعلق بالأداء أريد أن تجنب الكتابة إلى القرص. دعوة toString على ByteBuffer لا يعمل لأن السلسلة الناتجة كبيرة جدا (أنه يلقي java.lang.OutOfMemoryError: جافا كومة الفضاء). كنت أود أن يكون من شأنه أن الفكر أن يكون هناك شيء في API للالتفاف ByteBuffer في القارئ مناسبة، ولكن لا يمكنني العثور على ما يبدو أي شيء مناسب.

وإليك يختصر نموذج التعليمات البرمجية يوضح ما أقوم به):

// input stream is from Process getInputStream()
public String read(InputStream istream)
{
  ReadableByteChannel source = Channels.newChannel(istream);
  ByteArrayOutputStream ostream = new ByteArrayOutputStream(bufferSize);
  WritableByteChannel destination = Channels.newChannel(ostream);
  ByteBuffer buffer = ByteBuffer.allocateDirect(writeBufferSize);

  while (source.read(buffer) != -1)
  {
    buffer.flip();
    while (buffer.hasRemaining())
    {
      destination.write(buffer);
    }
    buffer.clear();
  }

  // this data can be up to 150 MB.. won't fit in a String.
  result = ostream.toString();
  source.close();
  destination.close();
  return result;
}

// after the process is run, we call this method with the String
public void readLines(String text)
{
  BufferedReader reader = new BufferedReader(new StringReader(text));
  String line;

  while ((line = reader.readLine()) != null)
  {
    // do stuff with line
  }
}
هل كانت مفيدة؟

المحلول

وليس من الواضح لماذا كنت تستخدم عازلة بايت لتبدأ. إذا كنت قد حصلت على InputStream وكنت ترغب في قراءة خطوط لذلك، لماذا لا مجرد استخدام InputStreamReader ملفوفة في BufferedReader؟ ما فائدة في الحصول على NIO المعنية؟

ودعوة toString() على ByteArrayOutputStream يبدو وكأنه فكرة سيئة بالنسبة لي حتى لو كان لديك مساحة له: الأفضل أن تحصل عليه في صفيف بايت والتفاف عليه في ByteArrayInputStream وبعد ذلك InputStreamReader، إذا كان لديك حقا أن يكون ByteArrayOutputStream. إذا كنت <م> حقا تريد الاتصال toString()، على الأقل استخدام الزائد الذي يأخذ اسم ترميز الأحرف الاستخدام - وإلا فإنه سوف تستخدم النظام الافتراضي، والتي ربما ليس ما تريد

وتحرير: حسنا، لذلك كنت تريد حقا أن استخدام NIO. كنت لا تزال الكتابة إلى ByteArrayOutputStream في نهاية المطاف، لذلك عليك في نهاية المطاف مع BAOS مع البيانات فيه. إذا كنت ترغب في تجنب الوقوع في نسخة من تلك البيانات، ستحتاج إلى تنبع من ByteArrayOutputStream، على سبيل المثال مثل هذا:

public class ReadableByteArrayOutputStream extends ByteArrayOutputStream
{
    /**
     * Converts the data in the current stream into a ByteArrayInputStream.
     * The resulting stream wraps the existing byte array directly;
     * further writes to this output stream will result in unpredictable
     * behavior.
     */
    public InputStream toInputStream()
    {
        return new ByteArrayInputStream(array, 0, count);
    }
}

وبعد ذلك يمكنك إنشاء تيار المدخلات، والتفاف عليه في InputStreamReader، والتفاف أنه في BufferedReader، وكنت بعيدا.

نصائح أخرى

ويمكنك استخدام NIO، ولكن ليس هناك حاجة حقيقية هنا. كما اقترح جون السكيت:

public byte[] read(InputStream istream)
{
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  byte[] buffer = new byte[1024]; // Experiment with this value
  int bytesRead;

  while ((bytesRead = istream.read(buffer)) != -1)
  {
    baos.write(buffer, 0, bytesRead);
  }

  return baos.toByteArray();
}


// after the process is run, we call this method with the String
public void readLines(byte[] data)
{
  BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(data)));
  String line;

  while ((line = reader.readLine()) != null)
  {
    // do stuff with line
  }
}

وهذه عينة:

public class ByteBufferBackedInputStream extends InputStream {

    ByteBuffer buf;

    public ByteBufferBackedInputStream(ByteBuffer buf) {
        this.buf = buf;
    }

    public synchronized int read() throws IOException {
        if (!buf.hasRemaining()) {
            return -1;
        }
        return buf.get() & 0xFF;
    }

    @Override
    public int available() throws IOException {
        return buf.remaining();
    }

    public synchronized int read(byte[] bytes, int off, int len) throws IOException {
        if (!buf.hasRemaining()) {
            return -1;
        }

        len = Math.min(len, buf.remaining());
        buf.get(bytes, off, len);
        return len;
    }
}

ويمكنك استخدامه مثل هذا:

    String text = "this is text";   // It can be Unicode text
    ByteBuffer buffer = ByteBuffer.wrap(text.getBytes("UTF-8"));

    InputStream is = new ByteBufferBackedInputStream(buffer);
    InputStreamReader r = new InputStreamReader(is, "UTF-8");
    BufferedReader br = new BufferedReader(r);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top