[工具类]文件或文件夹xx已存在,则重命名为xx(n)(2)
写在前面
最近一直在弄文件传输组件,其中一个功能就是,在接收端接收文件时,如果文件已经存在了,则对其进行文件名+索引的方式进行自动重命名,之前也写个类似的工具类,总感觉代码太冗余,每回头想想,总觉得心里有疙瘩,下班的时候在地铁上,又想了想,感觉是我把问题想复杂了,遂将今天的思路整理一下,写了一个辅助类,记录在此。
上篇文章
ReNameHelper代码
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks; namespace Wolfy.ReNameHelper
{
/// <summary>
/// 文件已存在,重命名操作类
/// </summary>
public class ReNameHelper
{
/// <summary>
/// 对文件进行重命名
/// </summary>
/// <param name="strFilePath"></param>
/// <returns></returns>
public static string FileReName(string strFilePath)
{
//判断该文件是否存在,存在则返回新名字,否则返回原来的名
if (!File.Exists(strFilePath))
{
return Path.GetFileName(strFilePath);
}
else
{
//获取不带扩展名的文件名称
string strFileNameWithoutExtension = Path.GetFileNameWithoutExtension(strFilePath);
//获取扩展名
string strFileExtension = Path.GetExtension(strFilePath);
//获取目录名
string strDirPath = Path.GetDirectoryName(strFilePath);
//以文件名开头和结尾的正则
string strRegex = "^" + strFileNameWithoutExtension + "(\\d+)?" ;
Regex regex = new Regex(strRegex);
//获取该路径下类似的文件名
string[] strFilePaths = Directory.GetFiles(strDirPath, "*" + strFileExtension).Where(path => regex.IsMatch(Path.GetFileNameWithoutExtension(path))).ToArray();
//获得新的文件名
return strFileNameWithoutExtension + "(" + (strFilePaths.Length + ).ToString() + ")" + strFileExtension;
}
}
/// <summary>
/// 文件夹已存在,重命名
/// </summary>
/// <param name="strFolderPath"></param>
/// <returns></returns>
public static string FolderReName(string strFolderPath)
{
//判断该文件夹是否存在,存在则返回新名字,否则返回原来的名
if (!Directory.Exists(strFolderPath))
{
return Path.GetFileName(strFolderPath);
}
else
{
//获取文件夹名
string strFolderName= Path.GetFileName(strFolderPath);
//获取目录名
string strDirPath = Path.GetDirectoryName(strFolderPath);
//以文件夹名开头和结尾的正则
string strRegex = "^" + strFolderName + "(\\d+)?";
Regex regex = new Regex(strRegex);
//获取该路径下类似的文件夹名
string[] strFilePaths = Directory.GetDirectories(strDirPath).Where(path => regex.IsMatch(Path.GetFileName(path))).ToArray();
//获得新的文件名
return strFolderName + "(" + (strFilePaths.Length + ).ToString() + ")" ;
}
}
}
}
实现思路:使用正则进行匹配以文件名或者文件夹名字开头的文件或者文件夹名称,获取文件或者文件夹的个数,则新的文件名为文件名(文件或者文件夹总数+1)。当然,对一些,名字比较特殊的,不符合windows命名规则的,在客户端选择文件或者文件夹的时候,尽量对其进行过滤。以保证该辅助类起到应有的作用。
简单测试
在路径C:\Users\Wolfy\Desktop\MVC5下有如上图的一些文件,现在如果再次接收相同名字的文件或者文件夹,则返回新的文件或者文件夹名
结果
这里也分享一个园友写的一个重命名的辅助类。对文件操作的辅助类,记录再次,供大家参考。
原文地址:http://www.cnblogs.com/lxblog/archive/2012/11/13/2768096.html
using System;
using System.Runtime.InteropServices;
using System.IO; namespace LxFile
{
/// <summary>
/// 文件操作代理,该类提供类似于Windows的文件操作体验
/// </summary>
public class FileOperateProxy
{
#region 【内部类型定义】
private struct SHFILEOPSTRUCT
{
public IntPtr hwnd; //父窗口句柄
public wFunc wFunc; //要执行的动作
public string pFrom; //源文件路径,可以是多个文件,以结尾符号"\0"结束
public string pTo; //目标路径,可以是路径或文件名
public FILEOP_FLAGS fFlags; //标志,附加选项
public bool fAnyOperationsAborted; //是否可被中断
public IntPtr hNameMappings; //文件映射名字,可在其它 Shell 函数中使用
public string lpszProgressTitle; // 只在 FOF_SIMPLEPROGRESS 时,指定对话框的标题。
} private enum wFunc
{
FO_MOVE = 0x0001, //移动文件
FO_COPY = 0x0002, //复制文件
FO_DELETE = 0x0003, //删除文件,只是用pFrom
FO_RENAME = 0x0004 //文件重命名
} private enum FILEOP_FLAGS
{
FOF_MULTIDESTFILES = 0x0001, //pTo 指定了多个目标文件,而不是单个目录
FOF_CONFIRMMOUSE = 0x0002,
FOF_SILENT = 0x0044, // 不显示一个进度对话框
FOF_RENAMEONCOLLISION = 0x0008, // 碰到有抵触的名字时,自动分配前缀
FOF_NOCONFIRMATION = 0x10, // 不对用户显示提示
FOF_WANTMAPPINGHANDLE = 0x0020, // 填充 hNameMappings 字段,必须使用 SHFreeNameMappings 释放
FOF_ALLOWUNDO = 0x40, // 允许撤销
FOF_FILESONLY = 0x0080, // 使用 *.* 时, 只对文件操作
FOF_SIMPLEPROGRESS = 0x0100, // 简单进度条,意味者不显示文件名。
FOF_NOCONFIRMMKDIR = 0x0200, // 建新目录时不需要用户确定
FOF_NOERRORUI = 0x0400, // 不显示出错用户界面
FOF_NOCOPYSECURITYATTRIBS = 0x0800, // 不复制 NT 文件的安全属性
FOF_NORECURSION = 0x1000 // 不递归目录
}
#endregion 【内部类型定义】 #region 【DllImport】 [DllImport("shell32.dll")]
private static extern int SHFileOperation(ref SHFILEOPSTRUCT lpFileOp); #endregion 【DllImport】 #region 【删除文件操作】
/// <summary>
/// 删除单个文件。
/// </summary>
/// <param name="fileName">删除的文件名</param>
/// <param name="toRecycle">指示是将文件放入回收站还是永久删除,true-放入回收站,false-永久删除</param>
/// <param name="showDialog">指示是否显示确认对话框,true-显示确认删除对话框,false-不显示确认删除对话框</param>
/// <param name="showProgress">指示是否显示进度对话框,true-显示,false-不显示。该参数当指定永久删除文件时有效</param>
/// <param name="errorMsg">反馈错误消息的字符串</param>
/// <returns>操作执行结果标识,删除文件成功返回0,否则,返回错误代码</returns>
public static int DeleteFile(string fileName, bool toRecycle, bool showDialog, bool showProgress, ref string errorMsg)
{
try
{
string fName = GetFullName(fileName);
return ToDelete(fName, toRecycle, showDialog, showProgress, ref errorMsg);
}
catch (Exception ex)
{
errorMsg = ex.Message;
return -;
}
} /// <summary>
/// 删除一组文件。
/// </summary>
/// <param name="fileNames">字符串数组,表示一组文件名</param>
/// <param name="toRecycle">指示是将文件放入回收站还是永久删除,true-放入回收站,false-永久删除</param>
/// <param name="showDialog">指示是否显示确认对话框,true-显示确认删除对话框,false-不显示确认删除对话框</param>
/// <param name="showProgress">指示是否显示进度对话框,true-显示,false-不显示。该参数当指定永久删除文件时有效</param>
/// <param name="errorMsg">反馈错误消息的字符串</param>
/// <returns>操作执行结果标识,删除文件成功返回0,否则,返回错误代码</returns>
public static int DeleteFiles(string[] fileNames, bool toRecycle, bool showDialog, bool showProgress, ref string errorMsg)
{
try
{
string fName = "";
foreach (string str in fileNames)
{
fName += GetFullName(str) + "\0"; //组件文件组字符串
} return ToDelete(fName, toRecycle, showDialog, showProgress, ref errorMsg);
}
catch (Exception ex)
{
errorMsg = ex.Message;
return -;
}
}
#endregion 【删除文件操作】 #region 【移动文件操作】
/// <summary>
/// 移动一个文件到指定路径下
/// </summary>
/// <param name="sourceFileName">要移动的文件名</param>
/// <param name="destinationPath">移动到的目的路径</param>
/// <param name="showDialog">指示是否显示确认对话框,true-显示确认对话框,false-不显示确认对话框</param>
/// <param name="showProgress">指示是否显示进度对话框</param>
/// <param name="autoRename">指示当文件名重复时,是否自动为新文件加上后缀名</param>
/// <param name="errorMsg">反馈错误消息的字符串</param>
/// <returns>返回移动操作是否成功的标识,成功返回0,失败返回错误代码</returns>
public static int MoveFile(string sourceFileName, string destinationPath, bool showDialog, bool showProgress, bool autoRename, ref string errorMsg)
{
try
{
string sfName = GetFullName(sourceFileName);
string dfName = GetFullName(destinationPath); return ToMoveOrCopy(wFunc.FO_MOVE, sfName, dfName, showDialog, showProgress, autoRename, ref errorMsg);
}
catch (Exception ex)
{
errorMsg = ex.Message;
return -;
}
} /// <summary>
/// 移动一组文件到指定的路径下
/// </summary>
/// <param name="sourceFileNames">要移动的文件名数组</param>
/// <param name="destinationPath">移动到的目的路径</param>
/// <param name="showDialog">指示是否显示确认对话框,true-显示确认对话框,false-不显示确认对话框</param>
/// <param name="showProgress">指示是否显示进度对话框</param>
/// <param name="autoRename">指示当文件名重复时,是否自动为新文件加上后缀名</param>
/// <param name="errorMsg">反馈错误消息的字符串</param>
/// <returns>返回移动操作是否成功的标识,成功返回0,失败返回错误代码,-200:表示其他异常</returns>
public static int MoveFiles(string[] sourceFileNames, string destinationPath, bool showDialog, bool showProgress, bool autoRename, ref string errorMsg)
{
try
{
string sfName = "";
foreach (string str in sourceFileNames)
{
sfName += GetFullName(str) + "\0"; //组件文件组字符串
}
string dfName = GetFullName(destinationPath); return ToMoveOrCopy(wFunc.FO_MOVE, sfName, dfName, showDialog, showProgress, autoRename, ref errorMsg);
}
catch (Exception ex)
{
errorMsg = ex.Message;
return -;
}
}
#endregion 【移动文件操作】 #region 【复制文件操作】
/// <summary>
/// 复制一个文件到指定的文件名或路径
/// </summary>
/// <param name="sourceFileName">要复制的文件名</param>
/// <param name="destinationFileName">复制到的目的文件名或路径</param>
/// <param name="showDialog">指示是否显示确认对话框,true-显示确认对话框,false-不显示确认对话框</param>
/// <param name="showProgress">指示是否显示进度对话框</param>
/// <param name="autoRename">指示当文件名重复时,是否自动为新文件加上后缀名</param>
/// <returns>返回移动操作是否成功的标识,成功返回0,失败返回错误代码,-200:表示其他异常</returns>
public static int CopyFile(string sourceFileName, string destinationFileName, bool showDialog, bool showProgress, bool autoRename, ref string errorMsg)
{
try
{
string sfName = GetFullName(sourceFileName);
string dfName = GetFullName(destinationFileName); return ToMoveOrCopy(wFunc.FO_COPY, sfName, dfName, showDialog, showProgress, autoRename, ref errorMsg);
}
catch (Exception ex)
{
errorMsg = ex.Message;
return -;
}
} /// <summary>
/// 复制一组文件到指定的路径
/// </summary>
/// <param name="sourceFileNames">要复制的文件名数组</param>
/// <param name="destinationPath">复制到的目的路径</param>
/// <param name="showDialog">指示是否显示确认对话框,true-显示确认对话框,false-不显示确认对话框</param>
/// <param name="showProgress">指示是否显示进度对话框</param>
/// <param name="autoRename">指示当文件名重复时,是否自动为新文件加上后缀名</param>
/// <returns>返回移动操作是否成功的标识,成功返回0,失败返回错误代码,-200:表示其他异常</returns>
public static int CopyFiles(string[] sourceFileNames, string destinationPath, bool showDialog, bool showProgress, bool autoRename, ref string errorMsg)
{
try
{
string sfName = "";
foreach (string str in sourceFileNames)
{
sfName += GetFullName(str) + "\0"; //组件文件组字符串
}
string dfName = GetFullName(destinationPath); return ToMoveOrCopy(wFunc.FO_COPY, sfName, dfName, showDialog, showProgress, autoRename, ref errorMsg);
}
catch (Exception ex)
{
errorMsg = ex.Message;
return -;
}
}
#endregion 【复制文件操作】 #region 【重命名文件】
/// <summary>
/// 重命名一个文件为新名称,建议您使用更方便的Microsoft.VisualBasic.FileSystem.ReName();替换该方法
/// </summary>
/// <param name="sourceFileName">要复制的文件名</param>
/// <param name="destinationFileName">复制到的目的文件名或路径</param>
/// <param name="showDialog">指示是否显示确认对话框,true-显示确认对话框,false-不显示确认对话框</param>
/// <returns>返回移动操作是否成功的标识,成功返回0,失败返回错误代码,-200:表示其他异常</returns>
[Obsolete("建议使用 Microsoft.VisualBasic.FileSystem.ReName()方法")]
public static int ReNameFile(string sourceFileName, string destinationFileName, bool showDialog, ref string errorMsg)
{ try
{
SHFILEOPSTRUCT lpFileOp = new SHFILEOPSTRUCT();
lpFileOp.wFunc = wFunc.FO_RENAME;
lpFileOp.pFrom = GetFullName(sourceFileName) + "\0\0"; //将文件名以结尾字符"\0\0"结束
lpFileOp.pTo = GetFullName(destinationFileName) + "\0\0"; lpFileOp.fFlags = FILEOP_FLAGS.FOF_NOERRORUI;
if (!showDialog)
lpFileOp.fFlags |= FILEOP_FLAGS.FOF_NOCONFIRMATION; //设定不显示提示对话框 lpFileOp.fAnyOperationsAborted = true; int n = SHFileOperation(ref lpFileOp);
if (n == )
return ; string tmp = GetErrorString(n); errorMsg = string.Format("{0}({1})", tmp, sourceFileName); return n;
}
catch (Exception ex)
{
errorMsg = ex.Message;
return -;
}
} /// <summary>
/// 利用Microsoft.VisualBasic.FileSystem.ReName()方法实现
/// </summary>
/// <param name="filePath"></param>
/// <param name="newFileName"></param>
public static void ReNameFile(string filePath, string newFileName)
{
try
{
string extensName = Path.GetExtension(filePath);
string newName = newFileName + extensName;
Microsoft.VisualBasic.FileIO.FileSystem.RenameFile(filePath, newName);
}
catch (Exception ex)
{
throw ex;
}
} #endregion 【重命名文件】 /// <summary>
/// 删除单个或多个文件
/// </summary>
/// <param name="fileName">删除的文件名,如果是多个文件,文件名之间以字符串结尾符'\0'隔开</param>
/// <param name="toRecycle">指示是将文件放入回收站还是永久删除,true-放入回收站,false-永久删除</param>
/// <param name="showDialog">指示是否显示确认对话框,true-显示确认删除对话框,false-不显示确认删除对话框</param>
/// <param name="showProgress">指示是否显示进度对话框,true-显示,false-不显示。该参数当指定永久删除文件时有效</param>
/// <param name="errorMsg">反馈错误消息的字符串</param>
/// <returns>操作执行结果标识,删除文件成功返回0,否则,返回错误代码</returns>
private static int ToDelete(string fileName, bool toRecycle, bool showDialog, bool showProgress, ref string errorMsg)
{
SHFILEOPSTRUCT lpFileOp = new SHFILEOPSTRUCT();
lpFileOp.wFunc = wFunc.FO_DELETE;
lpFileOp.pFrom = fileName + "\0"; //将文件名以结尾字符"\0"结束 lpFileOp.fFlags = FILEOP_FLAGS.FOF_NOERRORUI;
if (toRecycle)
lpFileOp.fFlags |= FILEOP_FLAGS.FOF_ALLOWUNDO; //设定删除到回收站
if (!showDialog)
lpFileOp.fFlags |= FILEOP_FLAGS.FOF_NOCONFIRMATION; //设定不显示提示对话框
if (!showProgress)
lpFileOp.fFlags |= FILEOP_FLAGS.FOF_SILENT; //设定不显示进度对话框 lpFileOp.fAnyOperationsAborted = true; int n = SHFileOperation(ref lpFileOp);
if (n == )
return ; string tmp = GetErrorString(n); //.av 文件正常删除了但也提示 402 错误,不知道为什么。屏蔽之。
if ((fileName.ToLower().EndsWith(".av") && n.ToString("X") == ""))
return ; errorMsg = string.Format("{0}({1})", tmp, fileName); return n;
} /// <summary>
/// 移动或复制一个或多个文件到指定路径下
/// </summary>
/// <param name="flag">操作类型,是移动操作还是复制操作</param>
/// <param name="sourceFileName">要移动或复制的文件名,如果是多个文件,文件名之间以字符串结尾符'\0'隔开</param>
/// <param name="destinationFileName">移动到的目的位置</param>
/// <param name="showDialog">指示是否显示确认对话框,true-显示确认对话框,false-不显示确认对话框</param>
/// <param name="showProgress">指示是否显示进度对话框</param>
/// <param name="autoRename">指示当文件名重复时,是否自动为新文件加上后缀名</param>
/// <param name="errorMsg">反馈错误消息的字符串</param>
/// <returns>返回移动操作是否成功的标识,成功返回0,失败返回错误代码</returns>
private static int ToMoveOrCopy(wFunc flag, string sourceFileName, string destinationFileName, bool showDialog, bool showProgress, bool autoRename, ref string errorMsg)
{
SHFILEOPSTRUCT lpFileOp = new SHFILEOPSTRUCT();
lpFileOp.wFunc = flag;
lpFileOp.pFrom = sourceFileName + "\0"; //将文件名以结尾字符"\0\0"结束
lpFileOp.pTo = destinationFileName + "\0\0"; lpFileOp.fFlags = FILEOP_FLAGS.FOF_NOERRORUI;
lpFileOp.fFlags |= FILEOP_FLAGS.FOF_NOCONFIRMMKDIR; //指定在需要时可以直接创建路径
if (!showDialog)
lpFileOp.fFlags |= FILEOP_FLAGS.FOF_NOCONFIRMATION; //设定不显示提示对话框
if (!showProgress)
lpFileOp.fFlags |= FILEOP_FLAGS.FOF_SILENT; //设定不显示进度对话框
if (autoRename)
lpFileOp.fFlags |= FILEOP_FLAGS.FOF_RENAMEONCOLLISION; //自动为重名文件添加名称后缀 lpFileOp.fAnyOperationsAborted = true; int n = SHFileOperation(ref lpFileOp);
if (n == )
return ; string tmp = GetErrorString(n); errorMsg = string.Format("{0}({1})", tmp, sourceFileName); return n;
} /// <summary>
/// 获取一个文件的全名
/// </summary>
/// <param name="fileName">文件名</param>
/// <returns>返回生成文件的完整路径名</returns>
private static string GetFullName(string fileName)
{
FileInfo fi = new FileInfo(fileName);
return fi.FullName;
} /// <summary>
/// 解释错误代码
/// </summary>
/// <param name="n">代码号</param>
/// <returns>返回关于错误代码的文字描述</returns>
private static string GetErrorString(int n)
{
if (n == ) return string.Empty; switch (n)
{
case :
return "系统找不到指定的文件。";
case :
return "存储控制块被销毁。您是否选择的“取消”操作?";
case :
return "文件已存在!";
case :
return "重命名文件操作,原始文件和目标文件必须具有相同的路径名。不能使用相对路径。";
case :
return "I/O控制错误";
case :
return "指定了重复的文件名";
case :
return "The source is a root directory, which cannot be moved or renamed.";
case :
return "Security settings denied access to the source.";
case :
return "The path in the source or destination or both was invalid.";
case :
return "An unspecified error occurred on the destination.";
case :
return "在试图移动或拷贝一个不存在的文件.";
case :
return "操作被取消!";
default:
return "未识别的错误代码:" + n;
}
}
}
}
总结
通过这个工具类的改写,发现实现一个功能,有很多方法,有时候换个思路,代码也许会更简洁,逻辑更清晰。
[工具类]文件或文件夹xx已存在,则重命名为xx(n)(2)的更多相关文章
- [工具类]文件或文件夹xx已存在,则重命名为xx(n)
写在前面 最近在弄一个文件传输的一个东东,在接收文件的时候,如果文件已经存在,该如何处理?提示?删除?感觉直接删除实在不太合适,万一这个文件对用户来说很重要,你给他删除了肯定不行.然后就想到了,win ...
- c#中@标志的作用 C#通过序列化实现深表复制 细说并发编程-TPL 大数据量下DataTable To List效率对比 【转载】C#工具类:实现文件操作File的工具类 异步多线程 Async .net 多线程 Thread ThreadPool Task .Net 反射学习
c#中@标志的作用 参考微软官方文档-特殊字符@,地址 https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/toke ...
- Property工具类,Properties文件工具类,PropertiesUtils工具类
Property工具类,Properties文件工具类,PropertiesUtils工具类 >>>>>>>>>>>>>& ...
- 【转载】 C#工具类:Csv文件转换类
CSV是逗号分隔值格式的文件,其文件以纯文本形式存储表格数据(数字和文本).CSV文件由任意数目的记录组成,记录间以某种换行符分隔:每条记录由字段组成,字段间的分隔符是其它字符或字符串,最常见的是逗号 ...
- 【转载】C#工具类:实现文件操作File的工具类
在应用程序的开发中,文件操作的使用基本上是必不可少的,FileStream类.StreamWriter类.Directory类.DirectoryInfo类等都是文件操作中时常涉及到的类,我们可以通过 ...
- Java常用工具类---IP工具类、File文件工具类
package com.jarvis.base.util; import java.io.IOException;import java.io.InputStreamReader;import jav ...
- Java常用工具类之删除文件
package com.wazn.learn.util; import java.io.File; /** * 删除文件工具类 * @author yangzhenyu * */ public cla ...
- 文件读取工具类读取properties文件
1.创建工具类 import java.io.IOException; import java.util.Properties; /** * * 类名称:PropertiesUtil * 类描述: 文 ...
- java工具类获取properties文件的配置
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.i ...
随机推荐
- Error && MFC
Error:MSB6006 "rc.exe" exited with code 2. 目录含有中文 Error:no instance of overloaded function ...
- ASP.NET中常用的几个李天平开源公共类LTP.Common,Maticsoft.DBUtility,LtpPageControl (转)
ASP.NET中常用的几个开源公共类: LTP.Common.dll: 通用函数类库 源码下载Maticsoft.DBUtility.dll 数据访问类库组件 源码下载LtpPageC ...
- 用Java实现单链表的基本操作
笔试题中经常遇到单链表的考题,下面用java总结一下单链表的基本操作,包括添加删除节点,以及链表转置. package mars; //单链表添加,删除节点 public class ListNode ...
- Linux 系统常用命令汇总(六) 文件打包与压缩
文件打包与压缩 命令 选项 注解 示例 compress 文件名 压缩指定的文件,压缩后的格式为*.z compress install.log -d 解压被压缩的文件 .z为后缀的文件:compr ...
- Listview的点击事件
上篇文章总结了如何自定义listview的显示内容,然而listview不能只是提供显示功能,还必须能够点击它显示一些东西: listView.setOnItemClickListener(new O ...
- [转载]ExtJs4 笔记(9) Ext.Panel 面板控件、 Ext.window.Window 窗口控件、 Ext.container.Viewport 布局控件
作者:李盼(Lipan)出处:[Lipan] (http://www.cnblogs.com/lipan/)版权声明:本文的版权归作者与博客园共有.转载时须注明本文的详细链接,否则作者将保留追究其法律 ...
- 三维网格形变算法(Laplacian-Based Deformation)
网格上顶点的Laplace坐标(均匀权重)定义为:,其中di为顶点vi的1环邻域顶点数. 网格Laplace坐标可以用矩阵形式表示:△=LV,其中,那么根据网格的Laplace坐标通过求解稀疏线性方程 ...
- java 静态方法和实例方法的区别
转自 java 静态方法和实例方法的区别 静态方法和实例方法的区别主要体现在两个方面: 在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法 ...
- iOS原生地图开发进阶——使用导航和附近兴趣点检索
iOS原生地图开发进阶——使用导航和附近兴趣点检索 iOS中的mapKit框架对国际化的支持非常出色.在前些篇博客中,对这个地图框架的基础用法和标注与覆盖物的添加进行了详细的介绍,这篇博客将介绍两个更 ...
- Spring 集成 RMI
Maven <dependency> <groupId>org.springframework</groupId> <artifactId>spring ...