日志记录类(明确FileStreamDictionary等用法)
分类:
IT文章
•
2025-01-23 12:11:43
一个好的程序对于日志的处理是必不可少的。好的日志记录可以帮助我们减少更好的查找错误和系统的维护。今天整理一下自己工作中平时用来记录日志的类,同时也补补基础知识。
功能: 根据程序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, "");
}
}
}
View Code
这个类基本就可以实现日志的记录啦,当然都是很基础的功能哈。自己在住程序中创建实体类,直接调用即可啦。
比如我在App.config文件中配置了路径: "D:studylog", 在主程序中调用如下:
public class Program
{
private static LogHelp log = new LogHelp("LogTest");
static void Main(string[] args)
{
log.WriteLine("Hello World");
}
}
View Code
直接运行程序,你就可以在D:studylogyyyymmddlogtest.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;
}
}
View Code
其他常见的属性和方法的说明:
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.关闭文件流