كيف يمكنني إلقاء نظرة خاطفة على أول بايتتين في InputStream؟

StackOverflow https://stackoverflow.com/questions/148130

سؤال

يجب أن تكون بسيطة جدًا:لدي InputStream حيث أريد إلقاء نظرة خاطفة على (عدم قراءة) أول بايتتين، أي.أريد أن يظل "الموضع الحالي" لـ InputStream عند 0 بعد إلقاء نظرة خاطفة عليه.ما هي الطريقة الأفضل والأكثر أمانا للقيام بذلك؟

إجابة - كما كنت أظن، كان الحل هو تغليفه في BufferedInputStream الذي يوفر إمكانية وضع علامة عليه.شكرا راسموس.

هل كانت مفيدة؟

المحلول

بالنسبة إلى InputStream عام، أود أن أقوم بتغليفه في BufferedInputStream وأقوم بشيء مثل هذا:

BufferedInputStream bis = new BufferedInputStream(inputStream);
bis.mark(2);
int byte1 = bis.read();
int byte2 = bis.read();
bis.reset();
// note: you must continue using the BufferedInputStream instead of the inputStream

نصائح أخرى

قد تجد أن PushbackInputStream مفيد:

http://docs.Oracle.com/javase/6/docs/api/Java/io/PushbackInputStream.html

عند استخدام BufferedInputStream، تأكد من أن inputStream لم يتم تخزينه مؤقتًا بالفعل، وسيتسبب التخزين المؤقت المزدوج في بعض الأخطاء التي يصعب العثور عليها.تحتاج أيضًا إلى التعامل مع القراء بشكل مختلف، فالتحويل إلى StreamReader والتخزين المؤقت سيؤدي إلى فقدان البايتات إذا كان القارئ مخزنًا مؤقتًا.أيضًا، إذا كنت تستخدم قارئًا، فتذكر أنك لا تقرأ وحدات البايت بل الأحرف الموجودة في التشفير الافتراضي (ما لم يتم تعيين ترميز صريح).مثال على دفق الإدخال المخزن مؤقتًا، والذي قد لا تعرفه هو URL url؛url.openStream();

ليس لدي أي مراجع لهذه المعلومات، فهي تأتي من تصحيح التعليمات البرمجية.الحالة الرئيسية التي حدثت فيها المشكلة بالنسبة لي كانت في التعليمات البرمجية التي تتم قراءتها من ملف إلى دفق مضغوط.إذا كنت أتذكر بشكل صحيح بمجرد بدء تصحيح الأخطاء من خلال التعليمات البرمجية، فهناك تعليقات في مصدر Java تفيد بأن بعض الأشياء لا تعمل بشكل صحيح دائمًا.لا أتذكر أين تأتي المعلومات من استخدام BufferedReader و BufferedInputStream ، لكنني أعتقد أن ذلك يفشل على الفور حتى على أبسط اختبار.تذكر لاختبار ذلك، يجب عليك تحديد حجم أكبر من حجم المخزن المؤقت (والذي يختلف بين BufferedReader وBufferedInputStream)، وتحدث المشاكل عندما تصل وحدات البايت التي تتم قراءتها إلى نهاية المخزن المؤقت.لاحظ أن هناك حجمًا للمخزن المؤقت للتعليمات البرمجية المصدر والذي يمكن أن يكون مختلفًا عن حجم المخزن المؤقت الذي قمت بتعيينه في المُنشئ.لقد مر وقت طويل منذ أن قمت بذلك، لذلك قد تكون ذكرياتي عن التفاصيل بعيدة بعض الشيء.تم إجراء الاختبار باستخدام FilterReader/FilterInputStream، وأضف واحدًا إلى الدفق المباشر وواحدًا إلى الدفق المخزن مؤقتًا لمعرفة الفرق.

لقد وجدت تطبيق PeekableInputStream هنا:

http://www.heatonresearch.com/articles/147/page2.html

فكرة التنفيذ الموضحة في المقالة هي أنها تحتفظ بمصفوفة من القيم "المطلعة" داخليًا.عند استدعاء القراءة، يتم إرجاع القيم أولاً من المصفوفة الخاطفة، ثم من دفق الإدخال.عند استدعاء النظرة الخاطفة، تتم قراءة القيم وتخزينها في المصفوفة "النظرة الخاطفة".

نظرًا لأن ترخيص نموذج التعليمات البرمجية هو LGPL، فيمكن إرفاقه بهذا المنشور:

package com.heatonresearch.httprecipes.html;

import java.io.*;

/**
 * The Heaton Research Spider Copyright 2007 by Heaton
 * Research, Inc.
 * 
 * HTTP Programming Recipes for Java ISBN: 0-9773206-6-9
 * http://www.heatonresearch.com/articles/series/16/
 * 
 * PeekableInputStream: This is a special input stream that
 * allows the program to peek one or more characters ahead
 * in the file.
 * 
 * This class is released under the:
 * GNU Lesser General Public License (LGPL)
 * http://www.gnu.org/copyleft/lesser.html
 * 
 * @author Jeff Heaton
 * @version 1.1
 */
public class PeekableInputStream extends InputStream
{

  /**
   * The underlying stream.
   */
  private InputStream stream;

  /**
   * Bytes that have been peeked at.
   */
  private byte peekBytes[];

  /**
   * How many bytes have been peeked at.
   */
  private int peekLength;

  /**
   * The constructor accepts an InputStream to setup the
   * object.
   * 
   * @param is
   *          The InputStream to parse.
   */
  public PeekableInputStream(InputStream is)
  {
    this.stream = is;
    this.peekBytes = new byte[10];
    this.peekLength = 0;
  }

  /**
   * Peek at the next character from the stream.
   * 
   * @return The next character.
   * @throws IOException
   *           If an I/O exception occurs.
   */
  public int peek() throws IOException
  {
    return peek(0);
  }

  /**
   * Peek at a specified depth.
   * 
   * @param depth
   *          The depth to check.
   * @return The character peeked at.
   * @throws IOException
   *           If an I/O exception occurs.
   */
  public int peek(int depth) throws IOException
  {
    // does the size of the peek buffer need to be extended?
    if (this.peekBytes.length <= depth)
    {
      byte temp[] = new byte[depth + 10];
      for (int i = 0; i < this.peekBytes.length; i++)
      {
        temp[i] = this.peekBytes[i];
      }
      this.peekBytes = temp;
    }

    // does more data need to be read?
    if (depth >= this.peekLength)
    {
      int offset = this.peekLength;
      int length = (depth - this.peekLength) + 1;
      int lengthRead = this.stream.read(this.peekBytes, offset, length);

      if (lengthRead == -1)
      {
        return -1;
      }

      this.peekLength = depth + 1;
    }

    return this.peekBytes[depth];
  }

  /*
   * Read a single byte from the stream. @throws IOException
   * If an I/O exception occurs. @return The character that
   * was read from the stream.
   */
  @Override
  public int read() throws IOException
  {
    if (this.peekLength == 0)
    {
      return this.stream.read();
    }

    int result = this.peekBytes[0];
    this.peekLength--;
    for (int i = 0; i < this.peekLength; i++)
    {
      this.peekBytes[i] = this.peekBytes[i + 1];
    }

    return result;
  }

}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top