Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Запись в txt файл 
:(
    Опции темы
pa6kevi4
  Дата 14.6.2010, 14:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 15.9.2009

Репутация: нет
Всего: нет



Здравствуйте, уважаемые винградовцы! 

Реализован класс, записывающий данные в txt файл.

Код

    class TxtLogger : ILogger
    {
        protected FileStream f1;
        protected string FileName = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\Folder\\Output1.txt";
        protected string CurrentLogText;
        protected StreamWriter output;
        protected Queue lgrMsg = new Queue();
        protected Object thisLock = new Object();      

        public void Log(string message, MessageType messageType)
        {
            lock (thisLock)
            {
                CurrentLogText = "Message text: " + message + ", " + DateTime.Now.ToString() + ", Type: " + messageType;
                lgrMsg.Enqueue(CurrentLogText);
                f1 = new FileStream(FileName, FileMode.Append);
                output = new StreamWriter(f1);
                while (lgrMsg.Count > 0)
                    output.WriteLine(lgrMsg.Dequeue());
                output.Close();
                f1.Close();
            }
        }
    }


Подскажите, как преобразовать его так, чтобы при повторном вызове метода Log в разных потоках:
1) не приходилось каждый раз открывать заново файл 
2) не приходилось ждать пока идёт запись (процесс записи занимает больше времени, чем получение данных (string message, MessageType messageType)), т.е сделать так, чтобы данные шли в очередь, и только потом записывались.

Спасибо за ваш форум!
PM MAIL   Вверх
pa6kevi4
  Дата 15.6.2010, 08:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 15.9.2009

Репутация: нет
Всего: нет



Цитата(pa6kevi4 @ 14.6.2010,  14:39)
Здравствуйте, уважаемые винградовцы! 

Реализован класс, записывающий данные в txt файл.

Код

    class TxtLogger : ILogger
    {
        protected FileStream f1;
        protected string FileName = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\Folder\\Output1.txt";
        protected string CurrentLogText;
        protected StreamWriter output;
        protected Queue lgrMsg = new Queue();
        protected Object thisLock = new Object();      

        public void Log(string message, MessageType messageType)
        {
            lock (thisLock)
            {
                CurrentLogText = "Message text: " + message + ", " + DateTime.Now.ToString() + ", Type: " + messageType;
                lgrMsg.Enqueue(CurrentLogText);
                f1 = new FileStream(FileName, FileMode.Append);
                output = new StreamWriter(f1);
                while (lgrMsg.Count > 0)
                    output.WriteLine(lgrMsg.Dequeue());
                output.Close();
                f1.Close();
            }
        }
    }


Подскажите, как преобразовать его так, чтобы при повторном вызове метода Log в разных потоках:
1) не приходилось каждый раз открывать заново файл 
2) не приходилось ждать пока идёт запись (процесс записи занимает больше времени, чем получение данных (string message, MessageType messageType)), т.е сделать так, чтобы данные шли в очередь, и только потом записывались.

Спасибо за ваш форум!

 smile 
PM MAIL   Вверх
PashaPash
Дата 15.6.2010, 09:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: 13
Всего: 49



pa6kevi4, полностью согласен со смайлом RTFM. Есть минимум 2 стандартных способа организовать логгирование -  System.Diagnostics.Trace и EntLib Logging App Block. Нечего изобретать велосипед.


--------------------
PM MAIL WWW   Вверх
ArchyDone
Дата 16.6.2010, 21:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 2.5.2010

Репутация: нет
Всего: нет



Код

 enum MessageType
    {
        System,
        Application,
        User,
        Error,
        Warning,
    }

    class LogMessage
    {
        private DateTime _messageTime;
        private String  _messageText;
        private String  _messageType;

        public LogMessage( DateTime _mtime , String _mtext, MessageType _mtype)
        {
            _messageTime = _mtime;
            _messageText = _mtext;

            switch (_mtype)
            {
                case MessageType.Application: _messageType = "Application"; break;
                case MessageType.System: _messageType = "System"; break;
                case MessageType.Error: _messageType = "Error"; break;
                case MessageType.User: _messageType = "User"; break;
                case MessageType.Warning: _messageType = "Warning"; break;
                default: _messageType = "Unknow"; break;
            }
        }

        public DateTime Time
        {
            get
            {
                return _messageTime;
            }
        }
        public String Text
        {
            get
            {
                return _messageText;
            }
        }
        public String Type
        {
            get
            {
                return _messageType;
            }
        }
    }


Код

class LogFile
    {
        //поток для записи символов  
        private StreamWriter _stream;
        //типизированная очередь ( тип каждого элемента LogMessage )
        private Queue<LogMessage> _queue;
        //максимальный размер очереди
        private Int32 _maxsize;
        //объект блокировки - нужен при выводе очереди в файл 
        private Object _locker;
        //переменная - путь . где размещен файл 
        private String _path;
        //рабочий поток , который и будет очищать очередь по достижении ее размера >= _maxsize
        private Thread _workThread;


        public LogFile(String path, Int32 s )
        {
            _path = path;
            _maxsize = s;
            _locker = new Object();
            _queue = new Queue<LogMessage>();
        }
        ~LogFile()
        {
            if (_queue.Count > 0)
            {
                CreateThread();
            }
        }
        public void AddMessage(LogMessage _message)
        {
            _queue.Enqueue(_message);

            if (_queue.Count >= _maxsize)
            {
                CreateThread();
            }
        }
       

        private void CreateThread()
        {
            _workThread = null;
            _workThread = new Thread(WriteFile);
            _workThread.Priority = ThreadPriority.BelowNormal;
            _workThread.Start();
        }
        private void WriteFile()
        {
            LogMessage message;

            lock (_locker)
            {
                using (_stream = new StreamWriter(_path, true, Encoding.Default))
                {
                    while( _queue.Count > 0 )
                    {
                         message = _queue.Dequeue();
                         _stream.WriteLine(String.Format("Время сообщения:{0}\t Тип сообщения:{1}\t Текст сообщения:{2}",
                                                             message.Time.ToLocalTime(),
                                                             message.Type, message.Text));
                    } 
                }
            }
        
        }

    }
}


Работает это так. Вы складываете свои сообщения в буфер - очередь. Размер очереди неограничен, или ограничен доступной памятью, но в переменной _maxsize Вы устанавливаете барьер.
Как только в буфер попадает очередное ( допустим 100 ) сообщение, то создается вторичный поток, который блокирует очередь , открывает файл с кодировкой которая стоит в системе , файл для дописания в конец и перебрасывает сообщения в текстовый файл. Главный поток свободен и может исполняться. 

Деструктор разрушающий объект проверят пустая ли очередь , если нет , то снова создает поток , который дописывает все что есть в очереди в файл. 

Поток _workThread не делайте фоновым 
_workThread.IsBackground = true; - ни в коем случае вот так! 
PM MAIL   Вверх
jonie
Дата 16.6.2010, 23:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 22
Всего: 118



Мои замечания:
1) никогда, никогда не делайте логирование в потоках - обычно логирование это "критичные вещи" , а не "все подряд" и, поверьте, когда ваша программа реально упадет, вам лучше не иметь буферов в памяти с логами ).. конечно, иногда это все же несправедливо
2) никогда не изобретайте велосипед.. в интернет куча проверенных логгеров есть
3) всегда в лог методах делайте try{} catch{ /* eat all */} - вам не захочется чттобы при логировании сыпалось приложение - как в примере постом выше при занятом файле например.
4) всегда явно закрывайте StrimeWriter в логгере - вы же знаете что будет если в методе Dispose потока, обернутого в using вызовется эксепшен, не так ли?)
5) если уж используете блокировку - используйте везде
6) а вообще логгер - типичный singleton
7)ну и конечно все знают про Synchronized метод в очереди (как пример)
8) всегда именуйте переменные понятными именами, а параметры тем более. Параметр "s" не является таковым.
9) вместо switch -а по enum-у, в котором нет пробелов, конечно использовать массив и enum как индекс эффективнее (да и смотрится изящнее)...
...
можно много критиковать в общем)


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
ArchyDone
Дата 18.6.2010, 19:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 2.5.2010

Репутация: нет
Всего: нет



2 jonie спасибо за конструктивную критику. 

Цитата

4) всегда явно закрывайте StrimeWriter в логгере - вы же знаете что будет если в методе Dispose потока, обернутого в using вызовется эксепшен, не так ли?)

Я честно не знаю , и если не отсылая за тридяведь  земель, поясните как может в методе Dispose вызваться экспепшен ?

Цитата

5) если уж используете блокировку - используйте везде

Разве я не использовал ее в нужном месте , что значит везде?  Пальцем ткните 

Цитата

6) а вообще логгер - типичный singleton
7)ну и конечно все знают про Synchronized метод в очереди (как пример)


Пояснения пожалуйста в студию

Цитата

9) вместо switch -а по enum-у, в котором нет пробелов, конечно использовать массив и enum как индекс эффективнее (да и смотрится изящнее)...


Примерчик плиз
PM MAIL   Вверх
jonie
Дата 19.6.2010, 13:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 22
Всего: 118



Цитата

Цитата

4) всегда явно закрывайте StrimeWriter в логгере - вы же знаете что будет если в методе Dispose потока, обернутого в using вызовется эксепшен, не так ли?)


Я честно не знаю , и если не отсылая за тридяведь  земель, поясните как может в методе Dispose вызваться экспепшен ?
поясняю:
Код

class FooClass : IDisposable {
 public override void Dispose() {
  // предположим у нас в Dispose не тривиальная логика, например
  //пусть наш класс проверяет не закрыт ли файл (а мы его не закрываем явно) и пытается его закрыть
  //так уже получилось, что наш класс выдал эксепшен при закрытии, вот эксепшен
  throw new Exception("oops... something wrong...");  
 }
}

....
using(var f = new FooClass()) {
 try{ /* используем f  */ } catch{ /* а мы-то думаем, что эксепшенов не будет, наивные */ }
} //привет, эксепшен - он будет в finally блоке, в который раскроется using


Цитата

Цитата

6) а вообще логгер - типичный singleton
Пояснения пожалуйста в студию

Singleton - паттерн проектирования (читать википедию например). В вашем логгере можно создать два инстанса одного логгера -> ваш логгер упадет из-за доступа к файлам (два логгера ваши не смогут писать в один файл).
Используйте например такой код:
Код

class Singleton {
 private static Singleton _instance;
 private Singleton( ) {}
 public static Singleton Instance {
  get {
   lock(typeof(Singleton)) {
    if(_instance == null) 
     _instance = new Singleton();
   retiurn _instance;
   }
  }
 }
}


Добавлено через 2 минуты и 54 секунды
Цитата

Цитата

9) вместо switch -а по enum-у, в котором нет пробелов, конечно использовать массив и enum как индекс эффективнее (да и смотрится изящнее)...

Примерчик плиз 



Код

 enum MessageType
    {
        System, /* 0 */
        Application, /* 1 */
        User,  /* 2 */
        Error, /* 3 */
        Warning, /* 4*/
    }

string[] MessageTypeStr = {"System", "Application", "User", "Error", "Warning" }

string Enum2Str(MessageType mr) {
 return MessageTypeStr[(int)mr];
}



--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.0501 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.