C# 使用文件流来读写ini文件

背景

  之前采用ini文件作为程序的配置文件,觉得这种结构简单明了,配置起来也挺方便。然后操作方式是通过WindowsAPI,然后再网上找到一个基于WindowsAPI封装的help类,用起来倒也顺手。用的多了,觉得还可以使用文件流来操作,后来就发现了EasyConfig。

  EasyConfig是一个纯C#的开源ini文件操作库,但是在使用上有诸多不便,只是个人感觉,于是个人将其改造了一下,是自己喜欢用的风格。

资源下载

  如果不清楚ini文件结构,请百度一下,这里贴一个示例文件。

  1.  Ini文件示例
  2. [Video]
  3. #是否全屏
  4. Fullscreen = true
  5. #宽度
  6. Width = 1280
  7. #电视高度
  8. #高度
  9. Height = 720
  10. [Level1]
  11. NumberOfEnemies=2000#数值
  12. Lives = 10
  13. Timer = 999
  14. EnemyNames = "Steve", "Sam", "Bill"
  15. EnemyGuns = 13, 28, 43, 499
  16. CanShoot = true, yes, on, no, false, off
  17. Ini文件示例

  EasyConfig 原版

  EasyConfig 改写后

代码示例

  首先来看看改写后,怎么去使用她来读写Ini文件。

  1. static void Main(string[] args)
  2. {
  3. ConfigFile configFile = new ConfigFile("Test.ini");
  4.  
  5. //遍历Config文件
  6. foreach (var group in configFile.SettingGroups)
  7. {
  8. Console.WriteLine("****************************");
  9. Console.WriteLine(group.Key + ":");
  10. Console.WriteLine();
  11.  
  12. foreach (var value in group.Value.Settings)
  13. Console.WriteLine("{0} = {1} (Is Array? {2}),{3}", value.Key, value.Value.RawValue, value.Value.IsArray, value.Value.Desp);
  14.  
  15. Console.WriteLine();
  16. }
  17. //读取值主要是在具体的配置项上进行读取,是首先定位到[Group],其次就是具体的项
  18. //使用泛型读取值,并指定读取失败时的默认值
  19. var fullScreen = configFile["Video"]["Fullscreen"].As<int>(-1);//失败
  20. var bFullScreen = configFile["Video"]["Fullscreen"].AsBool();//成功
  21. var arrCanShoot = configFile["Level1"]["CanShoot"].AsArray<bool>();
  22. //读取时 该项不存在,不存在的组或者项会自动添加
  23. var noexists = configFile["Video"]["xxxxxxxxxxx"].AsString();
  24. var noexists2 = configFile["Video111111111"]["xxxxxxxxxxx"].AsString();
  25.  
  26. //写入值有2种方法,可以直接向某组下写入一项,也可以定位到某组某项,写入值
  27. //写入值 该项不存在,组或者项会自动创建
  28. configFile["Video"].WriteSetting("NewName", "EasyConfig");
  29. configFile["Video"].WriteSetting("NewName", "EasyConfig2.0");
  30. configFile["Video22222222"].WriteSetting("c1", "1");
  31. //索引器不过是返回Setting
  32. configFile["Video3333"]["UserName"].SetValue("admin");
  33. configFile["Viedo4444"]["Sex"].SetValue("男", "女", "保密");
  34. //写入值,该项不存在
  35. configFile["Video222"].WriteSetting("NewName", "EasyConfig3.0");
  36.  
  37. Console.ReadKey(true);
  38.  
  39. configFile.Save("TestConfig2.txt");
  40. }

  基本上自己想要的效果,则是基于 ConfigFile["GroupName"]["Key"] 这样的方式来进行读写。

  另外附上一个基于WindowsAPI操作的封装类。

 IniFileHelp

/// <summary>
/// Provides methods for reading and writing to an INI file.
/// </summary>
public class IniFileHelp
{
/// <summary>
/// The maximum size of a section in an ini file.
/// </summary>
/// <remarks>
/// This property defines the maximum size of the buffers
/// used to retreive data from an ini file. This value is
/// the maximum allowed by the win32 functions
/// GetPrivateProfileSectionNames() or
/// GetPrivateProfileString().
/// </remarks>
public const int MaxSectionSize = 32767; // 32 KB

//The path of the file we are operating on.
private string m_path;

#region P/Invoke declares

/// <summary>
/// A static class that provides the win32 P/Invoke signatures
/// used by this class.
/// </summary>
/// <remarks>
/// Note: In each of the declarations below, we explicitly set CharSet to
/// Auto. By default in C#, CharSet is set to Ansi, which reduces
/// performance on windows 2000 and above due to needing to convert strings
/// from Unicode (the native format for all .Net strings) to Ansi before
/// marshalling. Using Auto lets the marshaller select the Unicode version of
/// these functions when available.
/// </remarks>
[System.Security.SuppressUnmanagedCodeSecurity]
private static class NativeMethods
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetPrivateProfileSectionNames(IntPtr lpszReturnBuffer,
uint nSize,
string lpFileName);

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern uint GetPrivateProfileString(string lpAppName,
string lpKeyName,
string lpDefault,
StringBuilder lpReturnedString,
int nSize,
string lpFileName);

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern uint GetPrivateProfileString(string lpAppName,
string lpKeyName,
string lpDefault,
[In, Out] char[] lpReturnedString,
int nSize,
string lpFileName);

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetPrivateProfileString(string lpAppName,
string lpKeyName,
string lpDefault,
IntPtr lpReturnedString,
uint nSize,
string lpFileName);

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetPrivateProfileInt(string lpAppName,
string lpKeyName,
int lpDefault,
string lpFileName);

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetPrivateProfileSection(string lpAppName,
IntPtr lpReturnedString,
uint nSize,
string lpFileName);

//We explicitly enable the SetLastError attribute here because
// WritePrivateProfileString returns errors via SetLastError.
// Failure to set this can result in errors being lost during
// the marshal back to managed code.
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool WritePrivateProfileString(string lpAppName,
string lpKeyName,
string lpString,
string lpFileName);

}
#endregion

/// <summary>
/// Initializes a new instance of the <see cref="IniFileHelp"/> class.
/// </summary>
/// <param name="path">The ini file to read and write from.</param>
public IniFileHelp(string path)
{
//Convert to the full path. Because of backward compatibility,
// the win32 functions tend to assume the path should be the
// root Windows directory if it is not specified. By calling
// GetFullPath, we make sure we are always passing the full path
// the win32 functions.
m_path = System.IO.Path.GetFullPath(path);
}

/// <summary>
/// Gets the full path of ini file this object instance is operating on.
/// </summary>
/// <value>A file path.</value>
public string Path
{
get
{
return m_path;
}
}

#region Get Value Methods

/// <summary>
/// Gets the value of a setting in an ini file as a <see cref="T:System.String"/>.
/// </summary>
/// <param name="sectionName">The name of the section to read from.</param>
/// <param name="keyName">The name of the key in section to read.</param>
/// <param name="defaultValue">The default value to return if the key
/// cannot be found.</param>
/// <returns>The value of the key, if found. Otherwise, returns
/// <paramref name="defaultValue"/></returns>
/// <remarks>
/// The retreived value must be less than 32KB in length.
/// </remarks>
/// <exception cref="ArgumentNullException">
/// <paramref name="sectionName"/> or <paramref name="keyName"/> are
/// a null reference (Nothing in VB)
/// </exception>
public string GetString(string sectionName,
string keyName,
string defaultValue)
{
if (sectionName == null)
throw new ArgumentNullException("sectionName");

if (keyName == null)
throw new ArgumentNullException("keyName");

StringBuilder retval = new StringBuilder(IniFileHelp.MaxSectionSize);

NativeMethods.GetPrivateProfileString(sectionName,
keyName,
defaultValue,
retval,
IniFileHelp.MaxSectionSize,
m_path);

return retval.ToString();
}

/// <summary>
/// Gets the value of a setting in an ini file as a <see cref="T:System.Int16"/>.
/// </summary>
/// <param name="sectionName">The name of the section to read from.</param>
/// <param name="keyName">The name of the key in section to read.</param>
/// <param name="defaultValue">The default value to return if the key
/// cannot be found.</param>
/// <returns>The value of the key, if found. Otherwise, returns
/// <paramref name="defaultValue"/>.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="sectionName"/> or <paramref name="keyName"/> are
/// a null reference (Nothing in VB)
/// </exception>
public int GetInt16(string sectionName,
string keyName,
short defaultValue)
{
int retval = GetInt32(sectionName, keyName, defaultValue);

return Convert.ToInt16(retval);
}

/// <summary>
/// Gets the value of a setting in an ini file as a <see cref="T:System.Int32"/>.
/// </summary>
/// <param name="sectionName">The name of the section to read from.</param>
/// <param name="keyName">The name of the key in section to read.</param>
/// <param name="defaultValue">The default value to return if the key
/// cannot be found.</param>
/// <returns>The value of the key, if found. Otherwise, returns
/// <paramref name="defaultValue"/></returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="sectionName"/> or <paramref name="keyName"/> are
/// a null reference (Nothing in VB)
/// </exception>
public int GetInt32(string sectionName,
string keyName,
int defaultValue)
{
if (sectionName == null)
throw new ArgumentNullException("sectionName");

if (keyName == null)
throw new ArgumentNullException("keyName");

return NativeMethods.GetPrivateProfileInt(sectionName, keyName, defaultValue, m_path);
}

/// <summary>
/// Gets the value of a setting in an ini file as a <see cref="T:System.Double"/>.
/// </summary>
/// <param name="sectionName">The name of the section to read from.</param>
/// <param name="keyName">The name of the key in section to read.</param>
/// <param name="defaultValue">The default value to return if the key
/// cannot be found.</param>
/// <returns>The value of the key, if found. Otherwise, returns
/// <paramref name="defaultValue"/></returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="sectionName"/> or <paramref name="keyName"/> are
/// a null reference (Nothing in VB)
/// </exception>
public double GetDouble(string sectionName,
string keyName,
double defaultValue)
{
string retval = GetString(sectionName, keyName, "");

if (retval == null || retval.Length == 0)
{
return defaultValue;
}

return Convert.ToDouble(retval, CultureInfo.InvariantCulture);
}

#endregion

#region GetSectionValues Methods

/// <summary>
/// Gets all of the values in a section as a list.
/// </summary>
/// <param name="sectionName">
/// Name of the section to retrieve values from.
/// </param>
/// <returns>
/// A <see cref="List{T}"/> containing <see cref="KeyValuePair{T1, T2}"/> objects
/// that describe this section. Use this verison if a section may contain
/// multiple items with the same key value. If you know that a section
/// cannot contain multiple values with the same key name or you don't
/// care about the duplicates, use the more convenient
/// <see cref="GetSectionValues"/> function.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="sectionName"/> is a null reference (Nothing in VB)
/// </exception>
public List<KeyValuePair<string, string>> GetSectionValuesAsList(string sectionName)
{
List<KeyValuePair<string, string>> retval;
string[] keyValuePairs;
string key, value;
int equalSignPos;

if (sectionName == null)
throw new ArgumentNullException("sectionName");

//Allocate a buffer for the returned section names.
IntPtr ptr = Marshal.AllocCoTaskMem(IniFileHelp.MaxSectionSize);

try
{
//Get the section key/value pairs into the buffer.
int len = NativeMethods.GetPrivateProfileSection(sectionName,
ptr,
IniFileHelp.MaxSectionSize,
m_path);

keyValuePairs = ConvertNullSeperatedStringToStringArray(ptr, len);
}
finally
{
//Free the buffer
Marshal.FreeCoTaskMem(ptr);
}

//Parse keyValue pairs and add them to the list.
retval = new List<KeyValuePair<string, string>>(keyValuePairs.Length);

for (int i = 0; i < keyValuePairs.Length; ++i)
{
//Parse the "key=value" string into its constituent parts
//Cancel a string start with '#'
var item = keyValuePairs[i].Trim();
if (item.Length > 0 && !item.StartsWith("#"))
{
equalSignPos = keyValuePairs[i].IndexOf('=');
key = keyValuePairs[i].Substring(0, equalSignPos);

value = keyValuePairs[i].Substring(equalSignPos + 1,
keyValuePairs[i].Length - equalSignPos - 1);

retval.Add(new KeyValuePair<string, string>(key, value));
}
}

return retval;
}

/// <summary>
/// Gets all of the values in a section as a dictionary.
/// </summary>
/// <param name="sectionName">
/// Name of the section to retrieve values from.
/// </param>
/// <returns>
/// A <see cref="Dictionary{T, T}"/> containing the key/value
/// pairs found in this section.
/// </returns>
/// <remarks>
/// If a section contains more than one key with the same name,
/// this function only returns the first instance. If you need to
/// get all key/value pairs within a section even when keys have the
/// same name, use <see cref="GetSectionValuesAsList"/>.
/// </remarks>
/// <exception cref="ArgumentNullException">
/// <paramref name="sectionName"/> is a null reference (Nothing in VB)
/// </exception>
public Dictionary<string, string> GetSectionValues(string sectionName)
{
List<KeyValuePair<string, string>> keyValuePairs;
Dictionary<string, string> retval;

keyValuePairs = GetSectionValuesAsList(sectionName);

//Convert list into a dictionary.
retval = new Dictionary<string, string>(keyValuePairs.Count);

foreach (KeyValuePair<string, string> keyValuePair in keyValuePairs)
{
//Skip any key we have already seen.
if (!retval.ContainsKey(keyValuePair.Key))
{
retval.Add(keyValuePair.Key, keyValuePair.Value);
}
}

return retval;
}

#endregion

#region Get Key/Section Names

/// <summary>
/// Gets the names of all keys under a specific section in the ini file.
/// </summary>
/// <param name="sectionName">
/// The name of the section to read key names from.
/// </param>
/// <returns>An array of key names.</returns>
/// <remarks>
/// The total length of all key names in the section must be
/// less than 32KB in length.
/// </remarks>
/// <exception cref="ArgumentNullException">
/// <paramref name="sectionName"/> is a null reference (Nothing in VB)
/// </exception>
public string[] GetKeyNames(string sectionName)
{
int len;
string[] retval;

if (sectionName == null)
throw new ArgumentNullException("sectionName");

//Allocate a buffer for the returned section names.
IntPtr ptr = Marshal.AllocCoTaskMem(IniFileHelp.MaxSectionSize);

try
{
//Get the section names into the buffer.
len = NativeMethods.GetPrivateProfileString(sectionName,
null,
null,
ptr,
IniFileHelp.MaxSectionSize,
m_path);

retval = ConvertNullSeperatedStringToStringArray(ptr, len);
}
finally
{
//Free the buffer
Marshal.FreeCoTaskMem(ptr);
}

return retval;
}

/// <summary>
/// Gets the names of all sections in the ini file.
/// </summary>
/// <returns>An array of section names.</returns>
/// <remarks>
/// The total length of all section names in the section must be
/// less than 32KB in length.
/// </remarks>
public string[] GetSectionNames()
{
string[] retval;
int len;

//Allocate a buffer for the returned section names.
IntPtr ptr = Marshal.AllocCoTaskMem(IniFileHelp.MaxSectionSize);

try
{
//Get the section names into the buffer.
len = NativeMethods.GetPrivateProfileSectionNames(ptr,
IniFileHelp.MaxSectionSize, m_path);

retval = ConvertNullSeperatedStringToStringArray(ptr, len);
}
finally
{
//Free the buffer
Marshal.FreeCoTaskMem(ptr);
}

return retval;
}

/// <summary>
/// Converts the null seperated pointer to a string into a string array.
/// </summary>
/// <param name="ptr">A pointer to string data.</param>
/// <param name="valLength">
/// Length of the data pointed to by <paramref name="ptr"/>.
/// </param>
/// <returns>
/// An array of strings; one for each null found in the array of characters pointed
/// at by <paramref name="ptr"/>.
/// </returns>
private static string[] ConvertNullSeperatedStringToStringArray(IntPtr ptr, int valLength)
{
string[] retval;

if (valLength == 0)
{
//Return an empty array.
retval = new string[0];
}
else
{
//Convert the buffer into a string. Decrease the length
//by 1 so that we remove the second null off the end.
string buff = Marshal.PtrToStringAuto(ptr, valLength - 1);

//Parse the buffer into an array of strings by searching for nulls.
retval = buff.Split('\0');
}

return retval;
}

#endregion

#region Write Methods

/// <summary>
/// Writes a <see cref="T:System.String"/> value to the ini file.
/// </summary>
/// <param name="sectionName">The name of the section to write to .</param>
/// <param name="keyName">The name of the key to write to.</param>
/// <param name="value">The string value to write</param>
/// <exception cref="T:System.ComponentModel.Win32Exception">
/// The write failed.
/// </exception>
private void WriteValueInternal(string sectionName, string keyName, string value)
{
if (!NativeMethods.WritePrivateProfileString(sectionName, keyName, value, m_path))
{
throw new System.ComponentModel.Win32Exception();
}
}

/// <summary>
/// Writes a <see cref="T:System.String"/> value to the ini file.
/// </summary>
/// <param name="sectionName">The name of the section to write to .</param>
/// <param name="keyName">The name of the key to write to.</param>
/// <param name="value">The string value to write</param>
/// <exception cref="T:System.ComponentModel.Win32Exception">
/// The write failed.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="sectionName"/> or <paramref name="keyName"/> or
/// <paramref name="value"/> are a null reference (Nothing in VB)
/// </exception>
public void WriteValue(string sectionName, string keyName, string value)
{
if (sectionName == null)
throw new ArgumentNullException("sectionName");

if (keyName == null)
throw new ArgumentNullException("keyName");

if (value == null)
throw new ArgumentNullException("value");

WriteValueInternal(sectionName, keyName, value);
}

/// <summary>
/// Writes an <see cref="T:System.Int16"/> value to the ini file.
/// </summary>
/// <param name="sectionName">The name of the section to write to .</param>
/// <param name="keyName">The name of the key to write to.</param>
/// <param name="value">The value to write</param>
/// <exception cref="T:System.ComponentModel.Win32Exception">
/// The write failed.
/// </exception>
public void WriteValue(string sectionName, string keyName, short value)
{
WriteValue(sectionName, keyName, (int)value);
}

/// <summary>
/// Writes an <see cref="T:System.Int32"/> value to the ini file.
/// </summary>
/// <param name="sectionName">The name of the section to write to .</param>
/// <param name="keyName">The name of the key to write to.</param>
/// <param name="value">The value to write</param>
/// <exception cref="T:System.ComponentModel.Win32Exception">
/// The write failed.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="sectionName"/> or <paramref name="keyName"/> are
/// a null reference (Nothing in VB)
/// </exception>
public void WriteValue(string sectionName, string keyName, int value)
{
WriteValue(sectionName, keyName, value.ToString(CultureInfo.InvariantCulture));
}

/// <summary>
/// Writes an <see cref="T:System.Single"/> value to the ini file.
/// </summary>
/// <param name="sectionName">The name of the section to write to .</param>
/// <param name="keyName">The name of the key to write to.</param>
/// <param name="value">The value to write</param>
/// <exception cref="T:System.ComponentModel.Win32Exception">
/// The write failed.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="sectionName"/> or <paramref name="keyName"/> are
/// a null reference (Nothing in VB)
/// </exception>
public void WriteValue(string sectionName, string keyName, float value)
{
WriteValue(sectionName, keyName, value.ToString(CultureInfo.InvariantCulture));
}

/// <summary>
/// Writes an <see cref="T:System.Double"/> value to the ini file.
/// </summary>
/// <param name="sectionName">The name of the section to write to .</param>
/// <param name="keyName">The name of the key to write to.</param>
/// <param name="value">The value to write</param>
/// <exception cref="T:System.ComponentModel.Win32Exception">
/// The write failed.
/// </exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="sectionName"/> or <paramref name="keyName"/> are
/// a null reference (Nothing in VB)
/// </exception>
public void WriteValue(string sectionName, string keyName, double value)
{
WriteValue(sectionName, keyName, value.ToString(CultureInfo.InvariantCulture));
}

#endregion

#region Delete Methods

/// <summary>
/// Deletes the specified key from the specified section.
/// </summary>
/// <param name="sectionName">
/// Name of the section to remove the key from.
/// </param>
/// <param name="keyName">
/// Name of the key to remove.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="sectionName"/> or <paramref name="keyName"/> are
/// a null reference (Nothing in VB)
/// </exception>
public void DeleteKey(string sectionName, string keyName)
{
if (sectionName == null)
throw new ArgumentNullException("sectionName");

if (keyName == null)
throw new ArgumentNullException("keyName");

WriteValueInternal(sectionName, keyName, null);
}

/// <summary>
/// Deletes a section from the ini file.
/// </summary>
/// <param name="sectionName">
/// Name of the section to delete.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="sectionName"/> is a null reference (Nothing in VB)
/// </exception>
public void DeleteSection(string sectionName)
{
if (sectionName == null)
throw new ArgumentNullException("sectionName");

WriteValueInternal(sectionName, null, null);
}

#endregion
}

IniFileHelp

MSD_radix_sort

 

一、这次是在上一次尝试基础上进行的,预期是达到上次性能的9倍。

MSD的基本手法就是不断切片。
每一步都是把整体数据切割成256片,如上图所示,实际情况切片未必均匀,有的slice内可能一个元素也没有。

接下来对于每个切片怎么办呢?
答案是继续切,对于特殊数据来讲,切片过程可以很快结束,这样就可以实现比LSD更快的速度。

这里面最困难的地方就是如何存储每个slice的头和尾。
如果采用下述方式,应该是行不通的。
这个方式需要做数组元素插入,还要跟踪中间数据,因此没具体考虑。

我真正采用的是下表:


表中第一项表示第一个元素开启一个类别,紧跟的0表示此元素和上面的1是同一类。
至于2表明在切片过程中是一个孤立的元素,后续就没必要再切片了。
这个方式可以大大简化编码。

二、伪代码。

  1. for each slice
  2. if slice-tag == 2 continue;
  3. if slice-tag == 1
  4. slice it;
  5. update bookkeeping
  1. int main(){
  2. HANDLE heap = NULL;
  3. Bucket bucket[BUCKETSLOTCOUNT];
  4. PageList * pageListPool;
  5. int plpAvailable = 0;
  6. int * pages = NULL;
  7. int * pagesAvailable = NULL;
  8. int * objIdx;
  9. unsigned short * s;
  10. __int8 * classifier = NULL;
  11.  
  12. time_t timeBegin;
  13. time_t timeEnd;
  14.  
  15. heap = HeapCreate(HEAP_NO_SERIALIZE|HEAP_GENERATE_EXCEPTIONS, 1024*1024, 0);
  16. if (heap != NULL){
  17. pages = (int * )HeapAlloc(heap, 0, (TFSI/PAGEGRANULAR + BUCKETSLOTCOUNT + 8) * PAGEAMOUNT);
  18. pageListPool = (PageList *)HeapAlloc(heap, 0, (TFSI/PAGEGRANULAR + 8) * sizeof(PageList));
  19. s = (unsigned short *)HeapAlloc(heap, 0, TFSI*sizeof(unsigned short));
  20. objIdx = (int *)HeapAlloc(heap, 0, TFSI * sizeof(int));
  21. classifier = (__int8 *)HeapAlloc(heap, 0, (TFSI+8)*sizeof(__int8));
  22. }
  23. MakeSure(pages != NULL && pageListPool != NULL && objIdx != NULL && classifier != NULL);
  24.  
  25. for(int i=0; i<TFSI; i++) objIdx[i]=i;
  26. timeBegin = clock();
  27. for (int i=0; i<TFSI; i++) s[i] = rand();
  28. timeEnd = clock();
  29. printf("\n%f(s) consumed in generating numbers", (double)(timeEnd-timeBegin)/CLOCKS_PER_SEC);
  30.  
  31. SecureZeroMemory(classifier, TFSI*sizeof(__int8));
  32. classifier[0] = 1;
  33. classifier[TFSI] = 1;
  34.  
  35. timeBegin = clock();
  36.  
  37. bool no_need_further_processing = false;
  38. for (int t=sizeof(short)-1; t>=0; t--){
  39. int bucketIdx;
  40. int slice_pointer = 0;
  41. int slice_base = 0;
  42. int flagCounter = 0;
  43.  
  44. if (no_need_further_processing) break;
  45.  
  46. //classifier: 1 new catagory
  47. //classifier: 2 completed catagory process
  48. while (slice_pointer < TFSI){
  49. if (classifier[slice_pointer] == 2){
  50. slice_base = slice_pointer;
  51. classifier[slice_base] = 0;
  52. while (classifier[slice_pointer] == 0){
  53. slice_pointer++;
  54. flagCounter++;
  55. }
  56. classifier[slice_base] = 2;
  57.  
  58. if (flagCounter == TFSI) no_need_further_processing = true;
  59. continue;
  60. }
  61.  
  62. if (classifier[slice_pointer] == 1){
  63. FillMemory(pages, (TFSI/PAGEGRANULAR + BUCKETSLOTCOUNT + 8) * PAGEAMOUNT, 0xff);
  64. SecureZeroMemory(pageListPool, (TFSI/PAGEGRANULAR + 8) * sizeof(PageList));
  65. pagesAvailable = pages;
  66. plpAvailable = 0;
  67.  
  68. for(int i=0; i<256; i++){
  69. bucket[i].currentPagePtr = pagesAvailable;
  70. bucket[i].offset = 0;
  71. bucket[i].pl.PagePtr = pagesAvailable;
  72. bucket[i].pl.next = NULL;
  73. pagesAvailable += PAGEGRANULAR;
  74. bucket[i].currentPageListItem = &(bucket[i].pl);
  75. }
  76.  
  77. slice_base = slice_pointer;
  78. classifier[slice_base] = 0;
  79. while (classifier[slice_pointer] == 0){
  80. //for each slice element, push_back to pages;
  81. unsigned char * cell = (unsigned char *)&s[objIdx[slice_pointer]];
  82. bucketIdx = cell[t];
  83. //save(bucketIdx, objIdx[i]);
  84. bucket[bucketIdx].currentPagePtr[ bucket[bucketIdx].offset ] = objIdx[slice_pointer];
  85. bucket[bucketIdx].offset++;
  86. if (bucket[bucketIdx].offset == PAGEGRANULAR){
  87. bucket[bucketIdx].currentPageListItem->next = &pageListPool[plpAvailable];
  88. plpAvailable++;
  89. bucket[bucketIdx].currentPageListItem->next->PagePtr = pagesAvailable;
  90. bucket[bucketIdx].currentPageListItem->next->next = NULL;
  91.  
  92. bucket[bucketIdx].currentPagePtr = pagesAvailable;
  93. bucket[bucketIdx].offset = 0;
  94. pagesAvailable += PAGEGRANULAR;
  95.  
  96. bucket[bucketIdx].currentPageListItem = bucket[bucketIdx].currentPageListItem->next;
  97. }
  98.  
  99. slice_pointer++;
  100. }
  101. classifier[slice_base] = 1;
  102.  
  103. //update classifier;
  104. //update objIdx index
  105. int start = slice_base;
  106. for (int i=0; i<256; i++){
  107. PageList * p;
  108. p = &(bucket[i].pl);
  109. //classifier: 1 new catagory
  110. //classifier: 2 complete catagory process
  111. classifier[start] = 1;
  112.  
  113. int counters = 0;
  114. while (p){
  115. for (int t=0; t<PAGEGRANULAR; t++){
  116. int idx = p->PagePtr[t];
  117. if (idx != TERMINATOR){
  118. objIdx[start] = idx;
  119. start++;
  120. counters++;
  121. }
  122. if (idx == TERMINATOR) break;
  123. }
  124. p = p->next;
  125. }
  126. if (counters == 1) classifier[start-1] = 2;
  127. }
  128. //update objIdx index
  129. } //if (classifier[slice_pointer] == 1)
  130. } //while (slice_pointer < TFSI)
  131. } //for (int t=sizeof(short)-1; t>=0; t--)
  132.  
  133. timeEnd = clock();
  134. printf("\n%f(s) consumed in generating results", (double)(timeEnd-timeBegin)/CLOCKS_PER_SEC);
  135.  
  136. //for(int i=0; i<TFSI; i++) printf("%d\n", s[objIdx[i]]);
  137.  
  138. HeapFree(heap, 0, pages);
  139. HeapFree(heap, 0, pageListPool);
  140. HeapFree(heap, 0, s);
  141. HeapFree(heap, 0, objIdx);
  142. HeapFree(heap, 0, classifier);
  143. HeapDestroy(heap);
  144.  
  145. return 0;
  146. }

三、测试

1024*1024*100 个短整型。

时间  5.438s

看到这里就知道杯具了,比LSD还慢。

如果应用到二维表,会更惨不忍睹。试了下果然如此。

四、讨论

如果哪位有更好的方法,欢迎讨论。

或者,基数排序只是一个花瓶?

 
 
分类: C/C++

读写ini文件的更多相关文章

  1. c# 利用动态库DllImport("kernel32")读写ini文件(提供Dmo下载)

    c# 利用动态库DllImport("kernel32")读写ini文件 自从读了设计模式,真的会改变一个程序员的习惯.我觉得嘛,经验也可以从一个人的习惯看得出来,看他的代码编写习 ...

  2. VB读写INI文件的四个函数以及相关API详细说明

    WritePrivateProfileString函数说明  来源:http://blog.csdn.net/wjb9921/article/details/2005000 在我们写的程序当中,总有一 ...

  3. C# 读写INI 文件

    INI 格式: [Section1] KeyWord1 = Value1 KeyWord2 = Value2 ... [Section2] KeyWord3 = Value3 KeyWord4 = V ...

  4. WIN32读写INI文件方法

      在程序中经常要用到设置或者其他少量数据的存盘,以便程序在下一次执行的时候可以使用,比如说保存本次程序执行时窗口的位置.大小.一些用户设置的 数据等等,在 Dos 下编程的时候,我们一般自己产生一个 ...

  5. 在 WinCe 平台读写 ini 文件

    在上篇文章开发 windows mobile 上的今日插件时,我发现 wince 平台上不支持例如 GetPrivateProfileString 等相关 API 函数.在网络上我并没有找到令我满意的 ...

  6. Windows中读写ini文件

    .ini 文件是Initialization File的缩写,即初始化文件,是windows的系统配置文件所采用的存储格式,来配置应用软件以实现不同用户的要求.配置文件有很多种如ini配置文件,XML ...

  7. C#中读写INI文件

    C#中读写INI文件 c#的类没有直接提供对ini文件的操作支持,可以自己包装win api的WritePrivateProfileString和GetPrivateProfileString函数实现 ...

  8. Qt读写ini文件

    一 背景 1 ini文件介绍 .ini 文件是Initialization File的缩写,即初始化文件. 除了windows现在很多其他操作系统下面的应用软件也有.ini文件,用来配置应用软件以实现 ...

  9. 【python-ini】python读写ini文件

    [python-ini]python读写ini文件 本文实例讲述了Python读写ini文件的方法.分享给大家供大家参考.具体如下: 比如有一个文件update.ini,里面有这些内容:   1 2 ...

随机推荐

  1. Android测试流量的几种方法

    1. tcpdump + wireshark 1.1 tcpdump抓包 注意:Android设备使用tcpdump需要root权限 tcpdump是一个在Unix-like系统中通用的网络抓包工具, ...

  2. c# 官方命名规则

    官方的哦. https://msdn.microsoft.com/zh-cn/library/vstudio/ff926074(v=vs.110).aspx

  3. likely()与unlikely()

    he gcc C compiler has a built-in directive that optimizes conditional branches as either very likely ...

  4. C#获取远程计算机硬件信息实例(支持linux和windows)

    原文:C#获取远程计算机硬件信息实例(支持linux和windows) 网上关于WMI的资料很多,但一直没有比较全的属性介绍.今天通过反射把所有属性都给弄出来了.   关于WMI的代码就不多说了.   ...

  5. Magicodes.NET框架

    Magicodes.NET框架之路——让代码再飞一会(ASP.NET Scaffolding)   首先感谢大家对Magicodes.NET框架的支持.就如我上篇所说,框架成熟可能至少还需要一年,毕竟 ...

  6. C语言双向链表

    原文:C语言双向链表 今天写了点双向链表的各种操作,写插入的时候费了点时间,不过,现在看来还是值得耗费那点时间去写的,这种小东西应该能信手拈来才行啊. /*双向链表*/ #include <st ...

  7. 使用gson和httpclient呼叫微信公众平台API

    吐槽:微信api很无语.有一部分xml.有一部分json. 最近看如何调用微信公众平台json有关api更方便.终于找到了httpcliect和gson对. 假设你有一个更好的办法,请告诉我. 了解如 ...

  8. Ubuntu Ruby On Rails安装和配置

    在这篇文章中ubuntu通过rvm安装ruby和rails.步借鉴了官方网站和网上信息,这里给大家分享. 1. 安装mapapis公钥: gpg --keyserver hkp://keys.gnup ...

  9. 深入了解 Java HelloWorld

    Java 的 Hello World 代码 public class HelloWorld { /** * * @param args */ public static void main(Strin ...

  10. 如何通过js获取iframe框架中的内容

    在父窗口中获取iframe中的元素 IE下:格式:window.frames["iframe的name值"].document.getElementById("ifram ...