سؤال

أنا أبحث عن فئة سريعة للعمل مع الملفات النصية وراحة قراءة كائن مختلف (طرق مثل NextInt32 ، NextDouble ، NextLine ، إلخ). هل يمكنك أن تنصحني بشيء؟

تعديل: BinaryReader هو فئة سيئة في حالتي. تنسيق بياناتي ليس ثنائيًا. لدي ملف مثل

1 2 3
FirstToken NextToken
1.23 2,34

وأريد قراءة هذا الملف برمز مثل:

int a = FileReader.NextInt32();
int b = FileReader.NextInt32();
int c = FileReader.NextInt32();
int d = FileReader.NextString();
int e = FileReader.NextString();
int f = FileReader.NextDouble();
int g = FileReader.NextDouble();

EDIT2: أبحث عن ماسح ضوئي تمثيلي من جافا

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

المحلول

سأضيف هذا كإجابة منفصلة لأنها متميزة تمامًا عن الإجابة التي قدمتها بالفعل. إليك كيف يمكنك البدء في إنشاء فئة الماسح الضوئي الخاص بك:

class Scanner : System.IO.StringReader
{
  string currentWord;

  public Scanner(string source) : base(source)
  {
     readNextWord();
  }

  private void ReadNextWord()
  {
     System.Text.StringBuilder sb = new StringBuilder();
     char nextChar;
     int next;
     do
     {
        next = this.Read();
        if (next < 0)
           break;
        nextChar = (char)next;
        if (char.IsWhiteSpace(nextChar))
           break;
        sb.Append(nextChar);
     } while (true);
     while((this.Peek() >= 0) && (char.IsWhiteSpace((char)this.Peek())))
        this.Read();
     if (sb.Length > 0)
        currentWord = sb.ToString();
     else
        currentWord = null;
  }

  public bool HasNextInt()
  {
     if (currentWord == null)
        return false;
     int dummy;
     return int.TryParse(currentWord, out dummy);
  }

  public int NextInt()
  {
     try
     {
        return int.Parse(currentWord);
     }
     finally
     {
        readNextWord();
     }
  }

  public bool HasNextDouble()
  {
     if (currentWord == null)
        return false;
     double dummy;
     return double.TryParse(currentWord, out dummy);
  }

  public double NextDouble()
  {
     try
     {
        return double.Parse(currentWord);
     }
     finally
     {
        readNextWord();
     }
  }

  public bool HasNext()
  {
     return currentWord != null;
  }
}

نصائح أخرى

أعتقد أن طريقة التمديد هذه TextReader سيفعل الحيلة:

public static class TextReaderTokenizer
{
    // Adjust as needed. -1 is EOF.
    private static int[] whitespace = { -1, ' ', '\r' , '\n', '\t' };

    public static T ReadToken<T>(this TextReader reader)
    {
        StringBuilder sb = new StringBuilder();
        while (Array.IndexOf(whitespace, reader.Peek()) < 0)
        {
            sb.Append((char)reader.Read());
        }
        return (T)Convert.ChangeType(sb.ToString(), typeof(T));
    }    
}

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

TextReader reader = File.OpenText("foo.txt");
int n = reader.ReadToken<int>();
string s = reader.ReadToken<string>();

تعديل كما هو مطلوب في تعليقات السؤال ، إليك نسخة غلاف مثيل مما سبق تم تصميمه مع المحددات و CultureInfo:

public class TextTokenizer
{
    private TextReader reader;
    private Predicate<char> isDelim;
    private CultureInfo cultureInfo;

    public TextTokenizer(TextReader reader, Predicate<char> isDelim, CultureInfo cultureInfo)
    {
        this.reader = reader;
        this.isDelim = isDelim;
        this.cultureInfo = cultureInfo;
    }

    public TextTokenizer(TextReader reader, char[] delims, CultureInfo cultureInfo)
    {
        this.reader = reader;
        this.isDelim = c => Array.IndexOf(delims, c) >= 0;
        this.cultureInfo = cultureInfo;
    }

    public TextReader BaseReader
    {
        get { return reader; }
    }

    public T ReadToken<T>()
    {
        StringBuilder sb = new StringBuilder();
        while (true)
        {
            int c = reader.Peek();
            if (c < 0 || isDelim((char)c))
            {
                break;
            }
            sb.Append((char)reader.Read());
        }
        return (T)Convert.ChangeType(sb.ToString(), typeof(T));
    }    
}

استخدام العينة:

TextReader reader = File.OpenText("foo.txt");
TextTokenizer tokenizer = new TextTokenizer(
    reader,
    new[] { ' ', '\r', '\n', '\t' },
    CultureInfo.InvariantCulture);
int n = tokenizer.ReadToken<int>();
string s = tokenizer.ReadToken<string>();

يجب أن تحدد بالضبط ما هو تنسيق ملفك هو أن تبدو. كيف تمثل سلسلة مع مساحة فيه؟ ما الذي يحدد أين تذهب محطات الخط؟

بشكل عام يمكنك استخدامه TextReader و ReadLine الطريقة ، تليها double.TryParse, int.TryParse إلخ - ولكن ستحتاج إلى تثبيت التنسيق لأسفل أولاً.

هل قمت بفحص فئة BinaryReader؟ نعم ، إنه ملف نصي ولكن لا يوجد شيء يمنعك من معاملته كبيانات ثنائية وبالتالي باستخدام BinaryReader. إنه يحتوي على جميع الطرق التي تبحث عنها باستثناء READLINE. ومع ذلك ، لن يكون من الصعب للغاية تنفيذ هذه الطريقة على رأس BinaryReader.

اذا أنت فعل تحتاج إلى ملفات نصية (أي UTF-8 أو ASCII الترميز) ثم لن يعمل الكاتب الثنائي.

يمكنك استعمال ال TextReader, ، ولكن على عكس BinaryReader و ال TextWriter لا يدعم أي أنواع أخرى غير الخط و char. سيتعين عليك تحديد ما هو مسموح بالفواصل وتحليل بيانات الأساس الخاصة بنفسك.

ال System.io.binaryReader الفصل هو ما تحتاجه.

مثال على تنفيذ أ readline طريقة:

public static class Extensions
{
    public static String ReadLine(this BinaryReader binaryReader)
    {
        var bytes = new List<Byte>();
        byte temp;

        while ((temp = (byte)binaryReader.Read()) < 10)
            bytes.Add(temp);

        return Encoding.Default.GetString(bytes.ToArray());
    }
}

مثال على استخدام هذه الفئة:

using System;
using System.IO;
using System.Security.Permissions;

class Test
{
    static void Main()
    {
        // Load application settings.
        AppSettings appSettings = new AppSettings();
        Console.WriteLine("App settings:\nAspect Ratio: {0}, " +
            "Lookup directory: {1},\nAuto save time: {2} minutes, " +
            "Show status bar: {3}\n",
            new Object[4]{appSettings.AspectRatio.ToString(),
            appSettings.LookupDir, appSettings.AutoSaveTime.ToString(),
            appSettings.ShowStatusBar.ToString()});

        // Change the settings.
        appSettings.AspectRatio   = 1.250F;
        appSettings.LookupDir     = @"C:\Temp";
        appSettings.AutoSaveTime  = 10;
        appSettings.ShowStatusBar = true;

        // Save the new settings.
        appSettings.Close();
    }
}

// Store and retrieve application settings.
class AppSettings
{
    const string fileName = "AppSettings#@@#.dat";
    float  aspectRatio;
    string lookupDir;
    int    autoSaveTime;
    bool   showStatusBar;

    public float AspectRatio
    {
        get{ return aspectRatio; }
        set{ aspectRatio = value; }
    }

    public string LookupDir
    {
        get{ return lookupDir; }
        set{ lookupDir = value; }
    }

    public int AutoSaveTime
    {
        get{ return autoSaveTime; }
        set{ autoSaveTime = value; }
    }

    public bool ShowStatusBar
    {
        get{ return showStatusBar; }
        set{ showStatusBar = value; }
    }

    public AppSettings()
    {
        // Create default application settings.
        aspectRatio   = 1.3333F;
        lookupDir     = @"C:\AppDirectory";
        autoSaveTime  = 30;
        showStatusBar = false;

        if(File.Exists(fileName))
        {
            BinaryReader binReader =
                new BinaryReader(File.Open(fileName, FileMode.Open));
            try
            {
                // If the file is not empty,
                // read the application settings.
                // First read 4 bytes into a buffer to
                // determine if the file is empty.
                byte[] testArray = new byte[3];
                int count = binReader.Read(testArray, 0, 3);

                if (count != 0)
                {
                    // Reset the position in the stream to zero.
                    binReader.BaseStream.Seek(0, SeekOrigin.Begin);

                    aspectRatio   = binReader.ReadSingle();
                    lookupDir     = binReader.ReadString();
                    autoSaveTime  = binReader.ReadInt32();
                    showStatusBar = binReader.ReadBoolean();
                }
            }

            // If the end of the stream is reached before reading
            // the four data values, ignore the error and use the
            // default settings for the remaining values.
            catch(EndOfStreamException e)
            {
                Console.WriteLine("{0} caught and ignored. " +
                    "Using default values.", e.GetType().Name);
            }
            finally
            {
                binReader.Close();
            }
        }

    }

    // Create a file and store the application settings.
    public void Close()
    {
        using(BinaryWriter binWriter =
            new BinaryWriter(File.Open(fileName, FileMode.Create)))
        {
            binWriter.Write(aspectRatio);
            binWriter.Write(lookupDir);
            binWriter.Write(autoSaveTime);
            binWriter.Write(showStatusBar);
        }
    }
}

ربما يمكنك استخدام System.io.file فئة لقراءة الملف و System.Convert لتحليل الأوتار التي تقرأها من الملف.

string line = String.Empty;
while( (line = file.ReadLine()).IsNullOrEmpty() == false )
{
   TYPE value = Convert.ToTYPE( line );
}

أين TYPE هو أي نوع تتعامل معه في هذا الخط / الملف المعين.

إذا كانت هناك قيم متعددة على سطر واحد ، فيمكنك القيام بتقسيم وقراءة القيم الفردية على سبيل المثال

string[] parts = line.Split(' ');
if( parts.Length > 1 )
{
   foreach( string item in parts )
   {
      TYPE value = Convert.ToTYPE( item );
   }
}
else
{
   // Use the code from before
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top