日志记录类(明确FileStream\Dictionary等用法)

一个好的程序对于日志的处理是必不可少的。好的日志记录可以帮助我们减少更好的查找错误和系统的维护。今天整理一下自己工作中平时用来记录日志的类,同时也补补基础知识。

功能: 根据程序App.config中配置的路径,创建日志文件并将程序的日志写到相应的文件中。

首先来看一下我之前自己写的一个用于写日志的类,源代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;

namespace LogHelp
{
    public class LogHelp
    {
        private string _filename;
        private static Dictionary<long, long> lockDic = new Dictionary<long, long>();

        //获取或设置文件名称
        public string FileName
        {
            get { return _filename; }
            set { _filename = value; }
        }

        //构造函数;根据传入的文件名,将日志写到相应的路径下的文件中。
        public LogHelp(string filename)
        {
            string folder = ConfigurationManager.AppSettings["LogPath"]+"\\"+System.DateTime.Now.Date.ToString("yyyyMMdd");
            if (!System.IO.Directory.Exists(folder))
                System.IO.Directory.CreateDirectory(folder);
            if (!filename.ToLower().EndsWith(".txt"))
            {
                filename = filename.Split(‘.‘)[0];
                filename += ".txt";
            }

            _filename = folder + "\\" + filename;
        }

        //创建文件
        public void Create(string fileName)
        {
            if (!System.IO.File.Exists(fileName))
            {
                using (System.IO.FileStream fs= System.IO.File.Create(fileName))
                {
                    fs.Close();
                }
            }
        }

        //写入文本
        private void Write(string content, string newLine)
        {
            if (string.IsNullOrEmpty(_filename))
            {
                throw new Exception("FileName不能为空!");
            }
            using(System.IO.FileStream fs=new System.IO.FileStream(_filename,System.IO.FileMode.OpenOrCreate,System.IO.FileAccess.ReadWrite,System.IO.FileShare.ReadWrite,8,System.IO.FileOptions.Asynchronous))
            {
                //FileStream只能处理字节,须通过编码将字符数据转换成字节。
                //新建字节型数组dataArrary对象,dataArrary对象得到了content+newLine的Encoding的值
                Byte[] dataArrary = System.Text.Encoding .Default.GetBytes(content+newLine);
                bool flag = true;
                long slen = dataArrary.Length;
                long len = 0;
                while (flag)
                {
                    try
                    {
                        if (len >= fs.Length)
                        {
                            fs.Lock(len, slen);
                            lockDic[len] = slen;
                            flag = false;
                        }
                        else
                        {
                            len = fs.Length;
                        }
                    }
                    catch (Exception ex)
                    {
                        while (!lockDic.ContainsKey(len))
                        {
                            len += lockDic[len];
                        }
                    }
                }
                fs.Seek(len, System.IO.SeekOrigin.Begin); //seek设置文件的读取和写入位置
                fs.Write(dataArrary, 0, dataArrary.Length);
                fs.Close();
            }
        }

        //写入文件内容
        public void WriteLine(string content)
        {
            this.Write(content, System.Environment.NewLine);
        }

        //写入文件
        public void Write(string content)
        {
            this.Write(content, "");
        }

    }
}

这个类基本就可以实现日志的记录啦,当然都是很基础的功能哈。自己在住程序中创建实体类,直接调用即可啦。

比如我在App.config文件中配置了路径: "D:\study\log", 在主程序中调用如下:

public class Program
{
     private static LogHelp log = new LogHelp("LogTest");
     static void Main(string[] args)
     {
         log.WriteLine("Hello World");
     }
}

直接运行程序,你就可以在D:\study\log\yyyymmdd\logtest.txt 文件中看到写入的”Hello World"啦。就这么简单,没什么可说的啦。

好啦,接下来,我们来看一下日志类中用到的Dictionary 和FileStream 用法的一些总结,加深了解,多了解没坏处啦。

Dictionary的用法总结:    

   需要引入命名空间: System.Collections.Generic (程序集:mscorlib)

Dictionary<string,string>是一个泛型,他本身有集合的功能有时可以把它看成数组;

他的结构是这样的: Dictionary<[key],[value]>,

他的特点是存入对象是需要与[key]值一一对应的存入该泛型;

1. 用法一、常规用

增加键值对之前需要判断是否存在该键,如果已经存在该键而且不判断,将抛出异常。所以这样每次都要进行判断,很麻烦,在备注使用了一个扩展方法:

构建一个Dictionary: Dictionary<string, string> plist = new Dictionary<string,string>;

读取Dictionary中的Key和Value,判断是否包含某个Key:  plist.ContainsKey("");

遍历Key: foreach(var key in plist.keys);

遍历Value: foreach(string value in plist.values);

遍历Key和Value: foreach(var dic in plist) { dic.key,dic.value};

2. 用法二、Dictionary的value为一个数组,代码示例如下:

public static void Sample()
{
   Dictionary<string,string[]> dic = new Dictionary<string,string[]>();
   string[] zhejiang = {"aa","bb","cc"};
   string[] shanghai = {“pudong","waitan"};
   dic.Add("ZJ", zhejiang);
   dic.Add("SH",shanghai);
}

3. 用法三、Dictionary的Value为一个类;

public static void Sample3()
{
   Dictionary<string, string> stuList = new Dictionary<string,string>();
   Student stu=null;
   for(int i=0; i<3;i++)
   {
      stu = new Student();
      stu.Num = i.ToString();
      stu.Name = "StuName"+i.ToString();
      stuList.Add(i.ToString(),stu);
   }
}

备注: Dictionary的扩展方法使用:

public static void DicSample4()
{
       //1)普通调用
        Dictionary<int, String> dict = new Dictionary<int, String>();
        DictionaryExtensionMethodClass.TryAdd(dict, 1, "ZhangSan");
        DictionaryExtensionMethodClass.TryAdd(dict, 2, "WangWu");
        DictionaryExtensionMethodClass.AddOrPeplace(dict, 3, "WangWu");
        DictionaryExtensionMethodClass.AddOrPeplace(dict, 3, "ZhangWu");
        DictionaryExtensionMethodClass.TryAdd(dict, 2, "LiSi");

        //2)TryAdd 和 AddOrReplace 这两个方法具有较强自我描述能力,用起来很省心,而且也简单:
        dict.AddOrPeplace(20, "Orange");
        dict.TryAdd(21, "Banana");
        dict.TryAdd(22, "apple");

        //3)像Linq或jQuery一样连起来写
        dict.TryAdd(10, "Bob")
              .TryAdd(11, "Tom")
              .AddOrPeplace(12, "Jom");
        //4) 获取值
        String F = "Ba";
        dict.TryGetValue(31, out F);
        Console.WriteLine("F : {0}",F);

        foreach (var dic in dict)
        {
            Console.WriteLine("Output : Key : {0}, Value : {1}", dic.Key, dic.Value);
        }
        //5)下面是使用GetValue获取值
        var v1 = dict.GetValue(111,null);
        var v2 = dict.GetValue(10,"abc");

        //6)批量添加
        var dict1 = new Dictionary<int,int>();
        dict1.AddOrPeplace(3, 3);
        dict1.AddOrPeplace(5, 5);

        var dict2 = new Dictionary<int, int>();
        dict2.AddOrPeplace(1, 1);
        dict2.AddOrPeplace(4, 4);
        dict2.AddRange(dict1, false);
  }
  扩展方法所在的类
    public static class DictionaryExtensionMethodClass
    {
        /// <summary>
        /// 尝试将键和值添加到字典中:如果不存在,才添加;存在,不添加也不抛导常
        /// </summary>
        public static Dictionary<TKey, TValue> TryAdd<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue value)
        {
            if (dict.ContainsKey(key) == false)
                dict.Add(key, value);
            return dict;
        }

        /// <summary>
        /// 将键和值添加或替换到字典中:如果不存在,则添加;存在,则替换
        /// </summary>
        public static Dictionary<TKey, TValue> AddOrPeplace<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue value)
        {
            dict[key] = value;
            return dict;
        }

        /// <summary>
        /// 获取与指定的键相关联的值,如果没有则返回输入的默认值
        /// </summary>
        public static TValue GetValue<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue defaultValue)
        {
            return dict.ContainsKey(key)?dict[key] : defaultValue;
        }

        /// <summary>
        /// 向字典中批量添加键值对
        /// </summary>
        /// <param name="replaceExisted">如果已存在,是否替换</param>
        public static Dictionary<TKey, TValue> AddRange<TKey, TValue>(this Dictionary<TKey, TValue> dict, IEnumerable<KeyValuePair<TKey, TValue>> values, bool replaceExisted)
        {
            foreach (var item in values)
            {
                if (dict.ContainsKey(item.Key) == false || replaceExisted)
                    dict[item.Key] = item.Value;
            }
            return dict;
        }

    }

其他常见的属性和方法的说明:

Comparer:  获取用于确定字段中键是否相等的IEqualityComparer;

Count:        获取包含在Dictionary中键值对的数目;

Item:           获取或设置与指定的键相关联的值;

Keys:          获取包含Dictionary中键的集合;

Values:       获取包含Dictionary中的值的集合;

Add:            将指定的键和值添加到字典中;

Clear:          从Dictionary中移除所有的键和值;

ContainsKey: 确定Dictionary是否包含指定的键;

ContainsValue: 确定Dictionary是否包含特定值;

GetEnumerator: 返回循环访问Dictionary的枚举值;

GetType:      获取当前实例的Type(从Object继承);

Remove:      从Dictionary中移除所指定的键的值;

ToString:      返回表示当前Object的String.(从Object继承);

TryGetValue:  获取与指定的键相关联的值。

FileStream用法总结:

引用命名空间: using System.IO

FileStream类只能处理原始字节(raw byte)。FileStream类可以用于任何数据文件,而不仅仅是文本文件。FileStream对象可以用于读取诸如图像和声音的文件,FileStream读取出来的是字节数组,然后通过编码转换将字节数组转换成字符串。

1. 读取文件:

第一步: 声明一个FileStream类的对象:

FileStream fsRead = new FileStream(string path, FileMode mode, FileAccess access);

参数:

path: 要操作文件的路径,路径可以是绝对路径或者相对路径;

mode: 操作文件的方式,打开或者创建;

access: 操作文件中的数据,读取或者写入。

第二步: 调用fsRead对象的方法Read;

下面方法是从文件中读取数据,再把数据写入一个字节数组;

FileStream.Read(byte[] array, int offset, int count);

参数:

array: 用了存储fsRead对象读取到数据的字节数组;

offset: 开始读取数据的位置,通常是0.

count: 最多读取的字节数。

2. 写入文件:

第一步: 声明一个FileStream类的对象:

FileStream fsWrite = new FileStream(string path, FileMode mode, FileAccess access);

第二步: 调用fsWrite对象的方法Write;

FileStream.Write(byte[] array, int offset, int count): 将字节数组数据写入到指定的文本。      

FileStream常用的属性和方法:

属性:

CanRead 判断当前流是否支持读取,返回bool值,True表示可以读取

CanWrite 判断当前流是否支持写入,返回bool值,True表示可以写入

方法:

Read() 从流中读取数据,返回字节数组

Write() 将字节块(字节数组)写入该流

Seek() 设置文件读取或写入的起始位置

Flush() 清除该流缓冲区,使得所有缓冲的数据都被写入到文件中

Close() 关闭当前流并释放与之相关联的所有系统资源

文件的访问方式:(FileAccess)

包括三个枚举:

FileAccess.Read(对文件读访问)

FileAccess.Write(对文件进行写操作)

FileAccess.ReadWrite(对文件读或写操作)

文件打开模式:(FileMode)包括6个枚举

FileMode.Append 打开现有文件准备向文件追加数据,只能同FileAccess.Write一起使用

FileMode.Create 指示操作系统应创建新文件,如果文件已经存在,它将被覆盖

FileMode.CreateNew 指示操作系统应创建新文件,如果文件已经存在,将引发异常

FileMode.Open 指示操作系统应打开现有文件,打开的能力取决于FileAccess所指定的值

FileMode.OpenOrCreate 指示操作系统应打开文件,如果文件不存在则创建新文件

FileMode.Truncate 指示操作系统应打开现有文件,并且清空文件内容

文件共享方式:(FileShare)

FileShare方式是为了避免几个程序同时访问同一个文件会造成异常的情况。

文件共享方式包括四个:

FileShare.None 谢绝共享当前文件

FileShare.Read 充许别的程序读取当前文件

FileShare.Write 充许别的程序写当前文件

FileShare.ReadWrite 充许别的程序读写当前文件

使用FileStream类创建文件流对象:

FileStream(String 文件路径,FileMode 文件打开模式)

FileStream(String 文件路径,FileMode 文件打开模式,FileAccess 文件访问方式)

FileStream(String 文件路径,FileMode 文件打开模式,FileAccess 文件访问方式,FileShare 文件共享方式)

使用File类来创建对象:(常用)

自定义打开文件的方式:File.Open(String,FileMode);

打开文件进行读取: File.OpenRead(String);

打开文件进行写入: File.OpenWrite(String);

注:

对文件的读写操多不管代码有多少,无非就是下面的三步:

1.创建文件读写流对象

2.对文件进行读写

3.关闭文件流

原文地址:https://www.cnblogs.com/erhanhan/p/8214685.html

时间: 2024-10-14 00:19:47

日志记录类(明确FileStream\Dictionary等用法)的相关文章

【个人使用.Net类库】(2)Log日志记录类

开发接口程序时,要保证程序稳定运行就要时刻监控接口程序发送和接收的数据,这就需要一个日志记录的类将需要的信息记录在日志文件中,便于自己维护接口程序.(Web系统也是如此,只是对应的日志实现比这个要复杂一点). 刚开始考虑的比较少,没有加入控制日志文件数量的功能.运行了一段时间,文件夹内的Log文件如下所示: 如果是这样,那运行一年不就三百多个日志文件了,想一想这太可怕了.通过查找资料,发现.Net中的FileInfo存有文件的信息(包括名称,创建时间,文件大小等),那就自己定义一个文件比较器实现

自定义错误日志记录类

引言 这是一个简单的自定义的错误日志记录类,这里我主要用于API接口开发中,APP移动端的入参记录 日志参数 /// <summary> /// 日志参数 /// </summary> public static class LogReq { /// <summary> /// 入参 /// </summary> public static string LogReqStr = ""; /// <summary> /// 加密

C# 创建自己的日志记录类 源码

调试及发布程序时,经常需要将一些信息输出保存,这里写了一个自己的日志记录类,记录信息更方便了.需要的话还可以进行更多的扩展,比如记录异常信息等. using System; using System.IO; namespace WindowsFormsApplication1 { public static class LogerHelper { #region 创建日志 ///-----------------------------------------------------------

改进的日志记录类

相对之前发的日志记录来说,此类将程序记录处理与写磁盘操作分离,用户代码部分,将日志放到队列,并通知线程将日志写到文件: 1.公共类: using System;using System.IO;using System.Collections.Generic;using static System.Console;using System.Text;using System.Diagnostics; namespace LogWriter{    /// <summary>    /// 日志类

日志记录类LogHelper

开源日志log4net使用起来很方便,但是项目中不让用,所以自己重写了一个类,用来记录日志,比较简单. 1.首先是可以把日志分成多个类型,分别记录到不同的文件中 1 /// <summary> 2 /// 日志类型 3 /// </summary> 4 public enum LogType 5 { 6 /// <summary> 7 /// 插入型 8 /// </summary> 9 Insert, 10 /// <summary> 11 /

【C#通用类】日志记录类

using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web; namespace KTCommon.LOG { public class TraceLog { /// <summary> /// 全局日志对象 /// </summary> pub

Spring AOP进行日志记录

在java开发中日志的管理有很多种.我一般会使用过滤器,或者是Spring的拦截器进行日志的处理.如果是用过滤器比较简单,只要对所有的.do提交进行拦截,然后获取action的提交路径就可以获取对每个方法的调用.然后进行日志记录.使用过滤器的好处是可以自己选择性的对某一些方法进行过滤,记录日志.但是实现起来有点麻烦. 另外一种就是使用Spring的AOP了.这种方式实现起来非常简单,只要配置一下配置文件就可以了.可是这种方式会拦截下所有的对action的每个操作.使得效率比较低.不过想做详细日志

【测试报告】-TestNG自定义日志记录

我们此前读TestNG的记录和报告提供了不同的选项.现在,让我们了解如何开始使用它们.首先,我们将编写一个示例程序,我们将使用的ITestListener接口,以便进行记录. 创建测试案例类 创建一个Java类为 SampleTest.java 在 C:\ > TestNG_WORKSPACE import org.testng.Assert; import org.testng.annotations.Test; public class SampleTest { @Test public v

Java 基于log4j的日志工具类

Java 基于log4j的日志工具类 对log4j日志类进行了简单封装,使用该封装类的优势在于以下两点: 1.不必在每个类中去创建对象,直接类名 + 方法即可 2.可以很方便的打印出堆栈信息 package com.tradeplatform.receiveorder.util; import java.io.PrintWriter; import java.io.StringWriter; import org.apache.log4j.Logger; /** * @Description 日