Last active
August 29, 2015 14:15
-
-
Save amankkg/5ff4c961a1585da7c2ff to your computer and use it in GitHub Desktop.
Fix for bad Cyrillic encoding in the name of files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// <copyright file="FileNamesEncoder.cs" company="none"> | |
// All is OK, guys! It's just a StyleCop-ism | |
// </copyright> | |
// <author>code4aman</author> | |
namespace FileNamesEncoder | |
{ | |
using System; | |
using System.IO; | |
using System.Linq; | |
using System.Text; | |
/// <summary> | |
/// encode file names and folder names, root path to start from must be defined, source and final encoding numbers are optional | |
/// </summary> | |
public class FileNamesEncoder | |
{ | |
#region Fields | |
/// <summary> | |
/// root directory to start from | |
/// </summary> | |
private string rootPath; | |
/// <summary> | |
/// bad names encoding number | |
/// </summary> | |
private int initialCodingNumber; | |
/// <summary> | |
/// names encoding number to-be | |
/// </summary> | |
private int finalCodingNumber; | |
#endregion | |
#region Constructors | |
/// <summary> | |
/// Initializes a new instance of the FileNamesEncoder class, default values assume cyrillic encoding problem for Windows (8.1) SL (english) edition (from CP437 to IBM866) | |
/// </summary> | |
/// <param name="root">folder to start from, required parameter</param> | |
/// <param name="sourceEncodingCode">initial encoding code/number, default is 437</param> | |
/// <param name="resultEncodingCode">final encoding code/number, default is 866</param> | |
public FileNamesEncoder(string root, int sourceEncodingCode = 437, int resultEncodingCode = 866) | |
{ | |
this.rootPath = root; | |
this.initialCodingNumber = sourceEncodingCode; | |
this.finalCodingNumber = resultEncodingCode; | |
} | |
#endregion | |
#region Properties | |
/// <summary> | |
/// Gets or sets root directory to start from | |
/// </summary> | |
public string RootPath | |
{ | |
get { return this.rootPath; } | |
set { this.rootPath = value; } | |
} | |
/// <summary> | |
/// Gets or sets bad names encoding number, (i.e. 437 for CP437) | |
/// </summary> | |
public int InitialCodingNumber | |
{ | |
get { return this.initialCodingNumber; } | |
set { this.initialCodingNumber = value; } | |
} | |
/// <summary> | |
/// Gets or sets names encoding number to-be (i.e. 866 for IBM866) | |
/// </summary> | |
public int FinalCodingNumber | |
{ | |
get { return this.finalCodingNumber; } | |
set { this.finalCodingNumber = value; } | |
} | |
#endregion | |
#region Public methods | |
/// <summary> | |
/// start processing folders, root = RootPath property | |
/// </summary> | |
public void StartProcessingDirectories() | |
{ | |
if (!Directory.Exists(this.rootPath)) | |
{ | |
this.ProcessDirectories(this.rootPath); | |
} | |
} | |
#endregion | |
#region Private methods | |
/// <summary> | |
/// renames folders (and subfolders, recursively) and files of each of them | |
/// </summary> | |
/// <param name="folderPath">start/root folder</param> | |
private void ProcessDirectories(string folderPath) | |
{ | |
var dirs = Directory.GetDirectories(folderPath).ToList(); | |
for (int i = 0; i < dirs.Count; i++) | |
{ | |
var oldName = Path.GetFileName(dirs[i]); | |
if (!this.ContainsCyrillicChar(oldName)) | |
{ | |
var newName = this.GetCorrectString(oldName); | |
// different newName means encoding was valuable and string has been modified | |
// if folder was renamed we should save it for RenameFolderFiles() use | |
if (oldName != newName) | |
{ | |
dirs[i] = this.RenameFolder(dirs[i], oldName, newName); | |
} | |
} | |
// processing each subfolder | |
this.ProcessDirectories(dirs[i]); | |
} | |
this.RenameFolderFiles(folderPath); | |
} | |
/// <summary> | |
/// renames folder | |
/// </summary> | |
/// <param name="oldPathWithName">full path with name included</param> | |
/// <param name="oldName">old folder name</param> | |
/// <param name="newName">new folder name</param> | |
/// <returns>name of resulting folder, if some errors occur then old name will be returned</returns> | |
private string RenameFolder(string oldPathWithName, string oldName, string newName) | |
{ | |
var resultPathWithName = oldPathWithName; | |
var newPathWithName = oldPathWithName.Replace(oldName, newName); | |
try | |
{ | |
Directory.Move(oldPathWithName, newPathWithName); | |
resultPathWithName = newPathWithName; | |
} | |
catch (IOException ex) | |
{ | |
this.WriteLog("Renaming folder " + newPathWithName + " __issued:__ " + ex.Message); | |
if (Directory.Exists(newPathWithName)) | |
{ | |
newPathWithName += "__MERGE_ME_"; | |
Directory.Move(oldPathWithName, newPathWithName); | |
resultPathWithName = newPathWithName; | |
this.WriteLog("Renaming folder " + newPathWithName + "successful"); | |
} | |
} | |
return resultPathWithName; | |
} | |
/// <summary> | |
/// renames all files in directory | |
/// </summary> | |
/// <param name="folderPath">path of directory</param> | |
private void RenameFolderFiles(string folderPath) | |
{ | |
var fileNames = Directory.GetFiles(folderPath).Select(p => Path.GetFileName(p)).ToList(); | |
for (int i = 0; i < fileNames.Count; i++) | |
{ | |
var oldName = fileNames[i]; | |
if (!this.ContainsCyrillicChar(oldName)) | |
{ | |
var newName = this.GetCorrectString(oldName); | |
// different newName means encoding was valuable and string has been modified | |
if (oldName != newName) | |
{ | |
this.RenameFile(folderPath, oldName, newName); | |
} | |
} | |
} | |
} | |
/// <summary> | |
/// renames folder | |
/// </summary> | |
/// <param name="folderPath">folder root path</param> | |
/// <param name="oldName">target folder name</param> | |
/// <param name="newName">new name</param> | |
private void RenameFile(string folderPath, string oldName, string newName) | |
{ | |
var oldPath = folderPath + "\\" + oldName; | |
var newPath = folderPath + "\\" + newName; | |
try | |
{ | |
File.Move(oldPath, newPath); | |
} | |
catch (Exception ex) | |
{ | |
this.WriteLog("Renaming file " + newPath + " __issued:__ " + ex.Message); | |
} | |
} | |
#endregion | |
#region HelperMethods | |
/// <summary> | |
/// checks if string contains cyrillic alphabet characters | |
/// </summary> | |
/// <param name="name">string to check</param> | |
/// <returns>true if contains any cyrillic char</returns> | |
private bool ContainsCyrillicChar(string name) | |
{ | |
// checking if file name contains any cyrillic chars, if true then file name is not 'bad encoded' | |
string alphabet = "абвгдеёжзийклмнопрстуфцхчшщъыьэюя"; | |
return name.ToLower().Any(c => alphabet.Contains(c)); | |
} | |
/// <summary> | |
/// converts source string from source encoding to result encoding, source and final encodings are taken from properties | |
/// </summary> | |
/// <param name="sourceString">string to convert</param> | |
/// <returns>encoded string</returns> | |
private string GetCorrectString(string sourceString) | |
{ | |
string resultString = sourceString; | |
var sourceEncoding = Encoding.GetEncoding(this.initialCodingNumber); | |
var resultEncoding = Encoding.GetEncoding(this.finalCodingNumber); | |
if (sourceEncoding != null && resultEncoding != null) | |
{ | |
resultString = resultEncoding.GetString(sourceEncoding.GetBytes(sourceString.ToCharArray())); | |
} | |
return resultString; | |
} | |
/// <summary> | |
/// prints messages log in console | |
/// </summary> | |
/// <param name="message">message text</param> | |
private void WriteLog(string message) | |
{ | |
Console.WriteLine("\t*\t*\t*"); | |
Console.WriteLine(DateTime.Now.ToString()); | |
Console.WriteLine(message); | |
Console.WriteLine("\t*\t*\t*\n"); | |
} | |
#endregion | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// example usage of FileNamesEncoder class | |
using System; | |
namespace FileNamesEncoder | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var encoder = new FileNamesEncoder("C:\\Users\\code4aman"); | |
encoder.StartProcessingDirectories(); | |
Console.WriteLine("\nFinished"); | |
Console.ReadLine(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
added regions