APK安装过程及原理详解

2023-10-31

应用程序包的安装是android的特点

APK为AndroidPackage的缩写

Android应用安装有如下四种方式:

1.系统应用安装――开机时完成,没有安装界面

2.网络下载应用安装――通过market应用完成,没有安装界面

3.ADB工具安装――没有安装界面。

4.第三方应用安装――通过SD卡里的APK文件安装,有安装界面,由         packageinstaller.apk应用处理安装及卸载过程的界面。

应用安装的流程及路径 
应用安装涉及到如下几个目录:        

system/app ---------------系统自带的应用程序,获得adb root权限才能删除

data/app  ---------------用户程序安装的目录。安装时把                                                                                                      apk文件复制到此目录
data/data ---------------存放应用程序的数据
data/dalvik-cache--------将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,其大小约为原始apk文件大小的四分之一)

安装过程:

复制APK安装包到data/app目录下,解压并扫描安装包,把dex文件(Dalvik字节码)保存到dalvik-cache目录,并data/data目录下创建对应的应用数据目录。

卸载过程:

删除安装过程中在上述三个目录下创建的文件及目录。

安装应用的过程解析

一.开机安装 
PackageManagerService处理各种应用的安装,卸载,管理等工作,开机时由systemServer启动此服务

(源文件路径:android\frameworks\base\services\java\com\android\server\PackageManagerService.java)

 

PackageManagerService服务启动的流程:

1.首先扫描安装“system\framework”目录下的jar包


           

 // Find base frameworks (resource packages without code).
            mFrameworkInstallObserver = new AppDirObserver(
                mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
            mFrameworkInstallObserver.startWatching();
            scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanMode | SCAN_NO_DEX, 0);

2.扫描安装系统system/app的应用程序

          

  // Collect all system packages.
            mSystemAppDir = new File(Environment.getRootDirectory(), "app");
            mSystemInstallObserver = new AppDirObserver(
                mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
            mSystemInstallObserver.startWatching();
            scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);

3.制造商的目录下/vendor/app应用包

           

 // Collect all vendor packages.
            mVendorAppDir = new File("/vendor/app");
            mVendorInstallObserver = new AppDirObserver(
                mVendorAppDir.getPath(), OBSERVER_EVENTS, true);
            mVendorInstallObserver.startWatching();
            scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);

4.扫描“data\app”目录,即用户安装的第三方应用

scanDirLI(mAppInstallDir, 0, scanMode, 0);


5.扫描" data\app-private"目录,即安装DRM保护的APK文件(一个受保护的歌曲或受保 护的视频是使用 DRM 保护的文件)

scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
                    scanMode, 0);


扫描方法的代码清单

private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {
        String[] files = dir.list();
        if (files == null) {
            Log.d(TAG, "No files in app dir " + dir);
            return;
        }
        if (false) {
            Log.d(TAG, "Scanning app dir " + dir);
        }
        int i;
        for (i=0; i<files.length; i++) {
            File file = new File(dir, files[i]);
            if (!isPackageFilename(files[i])) {
                // Ignore entries which are not apk's
                continue;
            }
            PackageParser.Package pkg = scanPackageLI(file,
                    flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime);
            // Don't mess around with apps in system partition.
            if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                    mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {
                // Delete the apk
                Slog.w(TAG, "Cleaning up failed install of " + file);
                file.delete();
            }
        }
    }


并且从该扫描方法中可以看出调用了scanPackageLI()

private PackageParser.Package scanPackageLI(File scanFile,

int parseFlags, int scanMode, long currentTime)

跟踪scanPackageLI()方法后发现,程序经过很多次的if else 的筛选,最后判定可以安装后调用了 mInstaller.install

if (mInstaller != null) {
                    int ret = mInstaller.install(pkgName, useEncryptedFSDir,  pkg.applicationInfo.uid,pkg.applicationInfo.uid);
                    if(ret < 0) {
                        // Error from installer
                        mLastScanError =    PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                        return null;
                    }
                }


mInstaller.install()  通过    

  LocalSocketAddress address = new LocalSocketAddress(

                "installd", LocalSocketAddress.Namespace.RESERVED);

指挥installd在C语言的文件中完成工作

PackageManagerService小节 :1)从apk, xml中载入pacakge信息, 存储到内部成员变量中, 用于后面的查找. 关键的方法是scanPackageLI().
2)各种查询操作, 包括query Intent操作.
3)install package和delete package的操作. 还有后面的关键方法是installPackageLI().

二、从网络上下载应用:

下载完成后,会自动调用Packagemanager的安装方法installPackage()

   

   /* Called when a downloaded package installation has been confirmed by the user */

    由英文注释可见PackageManagerService类的installPackage()函数为安装程序入口。

   

 public void installPackage(
            final Uri packageURI, final IPackageInstallObserver observer, final int flags,
            final String installerPackageName) {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.INSTALL_PACKAGES, null);
        Message msg = mHandler.obtainMessage(INIT_COPY);
        msg.obj = new InstallParams(packageURI, observer, flags,
                installerPackageName);
        mHandler.sendMessage(msg);
    }

其中是通过PackageHandler的实例mhandler.sendMessage(msg)把信息发给继承Handler的类HandleMessage()方法

class PackageHandler extends Handler{
                 
*****************省略若干********************
         public void handleMessage(Message msg) {
            try {
                doHandleMessage(msg);
            } finally {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            }
        }
   ******************省略若干**********************
 }


把信息发给doHandleMessage()方法,方法中用switch()语句进行判定传来Message

       

 void doHandleMessage(Message msg) {
            switch (msg.what) {
           
                case INIT_COPY: {
                    if (DEBUG_SD_INSTALL) Log.i(TAG, "init_copy");
                    HandlerParams params = (HandlerParams) msg.obj;
                    int idx = mPendingInstalls.size();
                    if (DEBUG_SD_INSTALL) Log.i(TAG, "idx=" + idx);
                    // If a bind was already initiated we dont really
                    // need to do anything. The pending install
                    // will be processed later on.
                    if (!mBound) {
                        // If this is the only one pending we might
                        // have to bind to the service again.
                        if (!connectToService()) {
                            Slog.e(TAG, "Failed to bind to media container service");
                            params.serviceError();
                            return;
                        } else {
                            // Once we bind to the service, the first
                            // pending request will be processed.
                            mPendingInstalls.add(idx, params);
                        }
                    } else {
                        mPendingInstalls.add(idx, params);
                        // Already bound to the service. Just make
                        // sure we trigger off processing the first request.
                        if (idx == 0) {
                            mHandler.sendEmptyMessage(MCS_BOUND);
                        }
                    }
                    break;
                }
                case MCS_BOUND: {
                    if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_bound");
                    if (msg.obj != null) {
                        mContainerService = (IMediaContainerService) msg.obj;
                    }
                    if (mContainerService == null) {
                        // Something seriously wrong. Bail out
                        Slog.e(TAG, "Cannot bind to media container service");
                        for (HandlerParams params : mPendingInstalls) {
                            mPendingInstalls.remove(0);
                            // Indicate service bind error
                            params.serviceError();
                        }
                        mPendingInstalls.clear();
                    } else if (mPendingInstalls.size() > 0) {
                        HandlerParams params = mPendingInstalls.get(0);
                        if (params != null) {
                            params.startCopy();
                        }
                    } else {
                        // Should never happen ideally.
                        Slog.w(TAG, "Empty queue");
                    }
                    break;
                }
            ****************省略若干**********************
}
}             

public final boolean sendMessage (Message msg)

public final boolean sendEmptyMessage (int what)

两者参数有别。

然后调用抽象类HandlerParams中的一个startCopy()方法

abstract class HandlerParams {

final void startCopy() {

   ***************若干if语句判定否这打回handler消息*******

handleReturnCode();

}
}

handleReturnCode()复写了两次其中有一次是删除时要调用的,只列出安装调用的一个方法

       

 @Override
        void handleReturnCode() {
            // If mArgs is null, then MCS couldn't be reached. When it
            // reconnects, it will try again to install. At that point, this
            // will succeed.
            if (mArgs != null) {
                processPendingInstall(mArgs, mRet);
            }
        }

这时可以清楚的看见 processPendingInstall()被调用。

其中run()方法如下

run(){
synchronized (mInstallLock) {
                        ************省略*****************
                        installPackageLI(args, true, res);
                   
 }
}
instaPacakgeLI()args,res参数分析


-----------------------------------------------------------------------------------------

//InstallArgs 是在PackageService定义的static abstract class InstallArgs 静态抽象类。

  

static abstract class InstallArgs {
*********************************************************************
其中定义了flag标志,packageURL,创建文件,拷贝apk,修改包名称,
                    还有一些删除文件的清理,释放存储函数。
    *********************************************************************
}
  class PackageInstalledInfo {
        String name;
        int uid;
        PackageParser.Package pkg;
        int returnCode;
        PackageRemovedInfo removedInfo;
 }

-----------------------------------------------------------------------------------------

  

  private void installPackageLI(InstallArgs args,
            boolean newInstall, PackageInstalledInfo res) {
        int pFlags = args.flags;
        String installerPackageName = args.installerPackageName;
        File tmpPackageFile = new File(args.getCodePath());
        boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
        boolean onSd = ((pFlags & PackageManager.INSTALL_EXTERNAL) != 0);
        boolean replace = false;
        int scanMode = (onSd ? 0 : SCAN_MONITOR) | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE
                | (newInstall ? SCAN_NEW_INSTALL : 0);
        // Result object to be returned
        res.returnCode = PackageManager.INSTALL_SUCCEEDED;
        // Retrieve PackageSettings and parse package
        int parseFlags = PackageParser.PARSE_CHATTY |
        (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) |
        (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
        parseFlags |= mDefParseFlags;
        PackageParser pp = new PackageParser(tmpPackageFile.getPath());
        pp.setSeparateProcesses(mSeparateProcesses);
        final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
                null, mMetrics, parseFlags);
        if (pkg == null) {
            res.returnCode = pp.getParseError();
            return;
        }
        String pkgName = res.name = pkg.packageName;
        if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
            if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
                res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;
                return;
            }
        }
        if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {
            res.returnCode = pp.getParseError();
            return;
        }
        // Get rid of all references to package scan path via parser.
        pp = null;
        String oldCodePath = null;
        boolean systemApp = false;
        synchronized (mPackages) {
            // Check if installing already existing package
            if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
                String oldName = mSettings.mRenamedPackages.get(pkgName);
                if (pkg.mOriginalPackages != null
                        && pkg.mOriginalPackages.contains(oldName)
                        && mPackages.containsKey(oldName)) {
                    // This package is derived from an original package,
                    // and this device has been updating from that original
                    // name.  We must continue using the original name, so
                    // rename the new package here.
                    pkg.setPackageName(oldName);
                    pkgName = pkg.packageName;
                    replace = true;
                } else if (mPackages.containsKey(pkgName)) {
                    // This package, under its official name, already exists
                    // on the device; we should replace it.
                    replace = true;
                }
            }
            PackageSetting ps = mSettings.mPackages.get(pkgName);
            if (ps != null) {
                oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
                if (ps.pkg != null && ps.pkg.applicationInfo != null) {
                    systemApp = (ps.pkg.applicationInfo.flags &
                            ApplicationInfo.FLAG_SYSTEM) != 0;
                }
            }
        }
        if (systemApp && onSd) {
            // Disable updates to system apps on sdcard
            Slog.w(TAG, "Cannot install updates to system apps on sdcard");
            res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
            return;
        }
        if (!args.doRename(res.returnCode, pkgName, oldCodePath)) {
            res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
            return;
        }
        // Set application objects path explicitly after the rename
        setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());
        pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();
        if (replace) {
            replacePackageLI(pkg, parseFlags, scanMode,
                    installerPackageName, res);
        } else {
            installNewPackageLI(pkg, parseFlags, scanMode,
                    installerPackageName,res);
        }
    }

 

最后判断如果以前不存在那么调用installNewPackageLI()

    

private void installNewPackageLI(PackageParser.Package pkg,
            int parseFlags,int scanMode,
            String installerPackageName, PackageInstalledInfo res) {
     ***********************省略若干*************************************************
        PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,
               System.currentTimeMillis());
     ***********************省略若干**************************************************  
}

最后终于回到了和开机安装一样的地方.与开机方式安装调用统一方法。

三、从ADB工具安装 

其入口函数源文件为pm.java 

(源文件路径:android\frameworks\base\cmds\pm\src\com\android\commands\pm\pm.java)

其中\system\framework\pm.jar 包管理库

包管理脚本 \system\bin\pm 解析

showUsage就是使用方法

private static void showUsage() { 
        System.err.println("usage: pm [list|path|install|uninstall]"); 
        System.err.println("       pm list packages [-f]"); 
        System.err.println("       pm list permission-groups"); 
        System.err.println("       pm list permissions [-g] [-f] [-d] [-u] [GROUP]"); 
        System.err.println("       pm list instrumentation [-f] [TARGET-PACKAGE]"); 
        System.err.println("       pm list features"); 
        System.err.println("       pm path PACKAGE"); 
        System.err.println("       pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH"); 
        System.err.println("       pm uninstall [-k] PACKAGE"); 
        System.err.println("       pm enable PACKAGE_OR_COMPONENT"); 
        System.err.println("       pm disable PACKAGE_OR_COMPONENT"); 
        System.err.println("       pm setInstallLocation [0/auto] [1/internal] [2/external]");
      **********************省略**************************
   }


安装时候会调用 runInstall()方法

  

  private void runInstall() {
        int installFlags = 0;
        String installerPackageName = null;
        String opt;
        while ((opt=nextOption()) != null) {
            if (opt.equals("-l")) {
                installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
            } else if (opt.equals("-r")) {
                installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
            } else if (opt.equals("-i")) {
                installerPackageName = nextOptionData();
                if (installerPackageName == null) {
                    System.err.println("Error: no value specified for -i");
                    showUsage();
                    return;
                }
            } else if (opt.equals("-t")) {
                installFlags |= PackageManager.INSTALL_ALLOW_TEST;
            } else if (opt.equals("-s")) {
                // Override if -s option is specified.
                installFlags |= PackageManager.INSTALL_EXTERNAL;
            } else if (opt.equals("-f")) {
                // Override if -s option is specified.
                installFlags |= PackageManager.INSTALL_INTERNAL;
            } else {
                System.err.println("Error: Unknown option: " + opt);
                showUsage();
                return;
            }
        }
        String apkFilePath = nextArg();
        System.err.println("\tpkg: " + apkFilePath);
        if (apkFilePath == null) {
            System.err.println("Error: no package specified");
            showUsage();
            return;
        }
        PackageInstallObserver obs = new PackageInstallObserver();
        try {
            mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags,
                    installerPackageName);
            synchronized (obs) {
                while (!obs.finished) {
                    try {
                        obs.wait();
                    } catch (InterruptedException e) {
                    }
                }
                if (obs.result == PackageManager.INSTALL_SUCCEEDED) {
                    System.out.println("Success");
                } else {
                    System.err.println("Failure ["
                            + installFailureToString(obs.result)
                            + "]");
                }
            }
        } catch (RemoteException e) {
            System.err.println(e.toString());
            System.err.println(PM_NOT_RUNNING_ERR);
        }
    }

其中的   

   

PackageInstallObserver obs = new PackageInstallObserver();

        

            mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags,

                    installerPackageName);

如果安装成功

obs.result == PackageManager.INSTALL_SUCCEEDED)

又因为有

IPackageManage mPm;

        mPm = IpackageManager.Stub.asInterface(ServiceManager.getService("package"));

Stub是接口IPackageManage的静态抽象类,asInterface是返回IPackageManager代理的静态方法。

因为class PackageManagerService extends IPackageManager.Stub

所以mPm.installPackage 调用 

    /* Called when a downloaded package installation has been confirmed by the user */

    public void installPackage(

            final Uri packageURI, final IPackageInstallObserver observer, final int flags,final String installerPackageName) 

这样就是从网络下载安装的入口了。

四,从SD卡安装

系统调用PackageInstallerActivity.java(/home/zhongda/androidSRC/vortex-8inch-for-hoperun/packages/apps/PackageInstaller/src/com/android/packageinstaller)

进入这个Activity会判断信息是否有错,然后调用

      private void initiateInstall()判断是否曾经有过同名包的安装,或者包已经安装

通过后执行private void startInstallConfirm() 点击OK按钮后经过一系列的安装信息的判断Intent跳转到

public class InstallAppProgress extends Activity implements View.OnClickListener, OnCancelListener
   public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        Intent intent = getIntent();
        mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
        mPackageURI = intent.getData();
        initView();
    }


方法中调用了initView()方法

   

 public void initView() {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.op_progress);
        int installFlags = 0;
        PackageManager pm = getPackageManager();
        try {
            PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName, 
                    PackageManager.GET_UNINSTALLED_PACKAGES);
            if(pi != null) {
                installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
            }
        } catch (NameNotFoundException e) {
        }
        if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) {
            Log.w(TAG, "Replacing package:" + mAppInfo.packageName);
        }
        PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, mAppInfo,
                mPackageURI);
        mLabel = as.label;
        PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
        mStatusTextView = (TextView)findViewById(R.id.center_text);
        mStatusTextView.setText(R.string.installing);
        mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
        mProgressBar.setIndeterminate(true);
        // Hide button till progress is being displayed
        mOkPanel = (View)findViewById(R.id.buttons_panel);
        mDoneButton = (Button)findViewById(R.id.done_button);
        mLaunchButton = (Button)findViewById(R.id.launch_button);
        mOkPanel.setVisibility(View.INVISIBLE);
        String installerPackageName = getIntent().getStringExtra(
                Intent.EXTRA_INSTALLER_PACKAGE_NAME);
        PackageInstallObserver observer = new PackageInstallObserver();
        pm.installPackage(mPackageURI, observer, installFlags, installerPackageName);
    }




方法最后我们可以看到再次调用安装接口完成安装。



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

APK安装过程及原理详解 的相关文章

  • 如何标准化字符串?

    在 NET 中 您可以使用以下方式规范化 NFC NFD NFKC NFKD 字符串String Normalize http msdn microsoft com en us library ebza6ck1 aspx并且有一个Text
  • 如何将双精度数转换为保留 2 位小数的字符串?

    我正在将这个双精度数转换为字符串 以便可以将其显示在 TextView 上 我希望使用 String format 使字符串具有 2 个小数位 但我不知道将其放在这行文本中的何处 Example setText Double toStrin
  • 如何在 JavaScript 中检查字符串是否包含子字符串数组中的文本?

    非常简单 在 javascript 中 我需要检查字符串是否包含数组中保存的任何子字符串 没有任何内置功能可以为您执行此操作 您必须为其编写一个函数 尽管它可能只是对some数组方法 两种方法适合您 Array some method 正则
  • 给定 2 个句子字符串计算余弦相似度

    From Python tf idf cosine 查找文档相似度 https stackoverflow com questions 12118720 python tf idf cosine to find document simil
  • 如何从整数生成 unicode 字符?

    我想创建一个 Unicode 字符数组 但我不知道如何将整数转换为 Unicode 表示形式 这是我到目前为止的代码 NSMutableArray uniArray NSMutableArray alloc initWithCapacity
  • Python 中的列表是否有等效的 str.split ?

    如果我有一个字符串 我可以用空格将其分割str split method hello world split returns hello world 如果我有一个像这样的列表 hey 1 None 2 0 string another st
  • Objective C iPhone 何时将对象引用设置为 nil

    我使用 Objective C 和 Cocoa 框架进行开发已经有一段时间了 然而 我仍然不太清楚 我什么时候应该将对象引用设置为 nil 我知道建议在释放具有委托的对象之前执行此操作 并且您还应该在保留子视图的 viewDidUnload
  • python 从字符串创建对象

    我有下一个情况 以下方法的目标是返回从传入字符串创建的对象 所以我有 class Situation Generator pass 以及父类中的方法 class Generator object def createsituation se
  • 将字符串数组转换为字节数组

    好吧 在有人试图将其标记为重复之前 我是not要求将字符串转换为字节数组 我想要一个字符串数组 包含类似这样的内容 5 168 188 28 29 155 转换为字节数组 我已经搜索过 只能找到字符串到字节数组 这是完全不同的 谢谢 编辑
  • 替换VBA中的变量字符串

    我需要替换字符串中的某些内容 但替换的内容可能会有所不同 有可能 XY test XXxY test XXyyXx TEST yXyy Test 以及几乎任何其他空格和上述情况的组合 我需要替换 test 部分并保留 XXX 所以 当使用简
  • Python 字符串格式 - 类型错误 - 格式字符串参数不足

    那么这个字符串有什么问题呢 我无法弄清楚为什么它说格式字符串没有足够的参数 我是 Python 新手 只是想弄清楚 编辑 这与建议的其他问题不同 另一个正在尝试做一些我什至没有涉及的疯狂数组事情 我只需要了解元组的基本概念以及字符串格式化的
  • 如何在 C++11 中将 u32string 转换为 int?

    我们怎样才能转换u32string to int在 C 11 中 另外 我应该使用什么方法将此类字符串的一部分转换为int 假设有开始和结束迭代器可用 我试过了 u32string test U 14 cout lt lt atoi tes
  • PHP中如何找出特定进程仍在运行

    我正在编写一个脚本 该脚本构建其他脚本的队列 并应该管理它们的启动 管理器脚本应该知道哪个子进程已经完成 因此它可以启动在队列中等待的其他脚本 我添加了一个 echo 获取每个子进程的进程 ID 所以我有我的子进程进程 ID 现在正在使用系
  • 如何在 C# 中从字符串调用委托?

    是否可以通过变量名称 作为字符串 调用存储在变量中的委托 我想我必须使用反射机制 但我没有得到任何结果 示例代码 class Demo public delegate int DemoDelegate private static int
  • 在C#中使用字符串调用变量

    我试图使用循环来编辑多个文本框的数据 但我无法弄清楚如何转换内容是我的框名称的字符串来访问每个框的文本元素 private void reset Click object sender EventArgs e string cell for
  • 将子字符串从 char* 复制到 std::string 的优雅方法

    我有这个char char line This is a great day string subLine 我要那个subLine会包括 is a great 从第 5 处复制 接下来的 10 个字符 有没有办法做到这一点而不是转换char
  • 如何使用正则表达式选择字符串中每个单词的第一个字母

    我试图使用正则表达式选择字符串中每个单词的第一个字母 但遇到了问题 我能够使用选择第一个单词的第一个字母 w igm 我如何修改它以选择字符串中每个单词的第一个字母 举个例子 我有字符串 我喜欢狗 我想要代码选择 I L 和 D Use a
  • Matlab中反转一位逻辑位

    是否存在更好的方法来反转 X 的元素 gt gt X dec2bin 10 X 1010 我这样做了 x i num2str 1 str2num x i 如果我理解正确的话 你想将一位设置为 1 使用bitset bitset x bitN
  • Java字符串查找和替换的最佳方法?

    我正在寻找 Java 中字符串查找和替换的最佳方法 这是一句话 我的名字叫米兰 人们都知道我叫米兰瓦西奇 我想用 Milan Vasic 替换 Milan 弦 但在我已经有 Milan Vasic 的地方 情况不应该是这样 搜索 替换后的结
  • 为什么在setsid()之前fork()

    Why fork before setsid 守护进程 基本上 如果我想将一个进程与其控制终端分离并使其成为进程组领导者 我使用setsid 之前没有分叉就这样做是行不通的 Why 首先 setsid 将使您的进程成为进程组的领导者 但它也

随机推荐

  • 树莓派的连接与AP局域网路由器配置

    文章目录 前言 1 树莓派的连接 1 1 本地连接 1 2 远程连接 2 AP路由器配置 2 1 配置无线局域网 2 2 配置以太网实现局域网 前言 树莓派的连接方式分为两种 本地和远程 也可以通俗的说是有本地设备还是就一台笔记本的情况 本
  • 解决:无法解析的外部符号__iob_func

    解决 无法解析的外部符号 iob func 原文 http blog csdn net hebbely article details 53780562 在使用 VS2015 下使用 libjpeg turbo 静态库 编译时报错了 cpp
  • 【用户增长】用户增长方法论及增长思维

    用户增长方法论及增长思维 1 什么是用户增长 1 1 用户增长的概念及内涵 用户增长不是简单的用户数量的增长 用户增长是一个系统化 综合化的体系 用户增长包含三个阶段的增长 综上三点 我们可以简单的将用户增长定义为 通过痛点 产品 渠道 创
  • 编写第一个Makefile(HelloWorld)

    什么是Makefile 讲makefie之前 先将将什么是make make是一个命令工具 是一个解释makefile中指令的命令工具 它可以简化编译过程里面所下达的指令 当执行 make 时 make 会在当前的目录下搜寻 Makefil
  • 建站系列(八)--- 本地开发环境搭建(WNMP)

    目录 相关系列文章 前言 一 准备工作 二 Nginx安装 三 MySQL安装 四 PHP安装及Nginx配置 五 总结 相关系列文章 建站系列 一 网站基本常识 建站系列 二 域名 IP地址 URL 端口详解 建站系列 三 网络协议 建站
  • ServletConfig对象

    目录 一 ServletConfig对象定义 二 ServletConfig对象作用 三 ServletConfig中的方法 一 ServletConfig对象定义 ServletConfig是什么 ServletConfig是一个接口 位
  • 3. 无重复字符的最长子串

    给定一个字符串 s 请你找出其中不含有重复字符的 最长子串 的长度 示例 1 输入 s abcabcbb 输出 3 解释 因为无重复字符的最长子串是 abc 所以其长度为 3 示例 2 输入 s bbbbb 输出 1 解释 因为无重复字符的
  • [转]iPhone多渠道自动打包Shell脚本介绍

    转 iPhone多渠道自动打包Shell脚本介绍 摘要 随着苹果手持设备用户的不断增加 ios应用也增长迅速 同时随着iphone被越狱越来越多的app 的渠道也不断增多 为各个渠道打包成了一件费时费力的工作 本文提供一种比较智能的打包方式
  • Java方法递归的简单例题

    目录 递归 1 递归求N 的阶乘和递归求1 2 3 4 n 2 按顺序打印一个数字的每一位 3 斐波那契数列和青蛙跳台阶问题 4 汉诺塔问题 递归 递归 简单来说 就是方法自己调用自己的过程 那要怎么样去实现递归呢 首先 我们需要去根据条件
  • 单页面(SPA)与服务端渲染(SSR),概念、区别,优缺点

    单页面 SPA 与服务端渲染 SSR 概念 区别 优缺点 什么是单页面应用 什么是多页面应用 二者有什么区别 1 单页面应用与多页面应用 单页面顾名思义就是整个应用只有一个Html页面 页面的切换其实是组件的切换 这样设计的好处就是不进行页
  • 多元回归分析

    多元回归分析 RF随机森林多输入单输出预测及变量重要度衡量 Matlab完整程序 目录 多元回归分析 RF随机森林多输入单输出预测及变量重要度衡量 Matlab完整程序 预测结果 评价指标 基本介绍 程序设计 参考资料 预测结果 评价指标
  • 进程——wait函数

    wait 的函数原型是 include
  • 使用Vue-Cli4.x配置文件路径别名

    vue脚手架版本升级到4 x以后 目录发生了很大的变化 有些配置需要我们自己去配置 自己项目中的目录结构 在根目录创建一个 vue config js文件 配置一下引入文件路径的别名 const path require path cons
  • C++报错 invalid operands to binary expression

    invalid operands to binary expression 二进制表达式的操作数无效 顾名思义 错误出在操作符上 对类型的操作问题 比如两种不能比较的类型进行了比较 比如我这里
  • 剑指Offer第三十一题:整数中1出现的次数(从1到n整数中1出现的次数)

    题目描述 求出1 13的整数中1出现的次数 并算出100 1300的整数中1出现的次数 为此他特别数了一下1 13中包含1的数字有1 10 11 12 13因此共出现6次 但是对于后面问题他就没辙了 ACMer希望你们帮帮他 并把问题更加普
  • 组合pig和hive来进行数据分析

    接到产品一个任务 需要对使用产品的用户操作系统来个分析 对清洗后的hive数据进行分析 发现 数据恰恰把操作系统数据 进行了过滤 只有到rawlog里去进行数据分析了 但由于rawlog没有和数据库进行关联 就只有先对rawlog进行初步手
  • Kotlin Lambda和高阶函数

    Lambda和高阶函数 本文链接 文章目录 Lambda和高阶函数 lambda 输出 返回类型 深入探究 泛型 inline原理探究 高阶函数 集合 泛型 自己实现Kotlin内置函数 扩展函数原理 companion object 原理
  • java解析zip文件(无需解压即可解析)

    个人原创博客 德鲁大叔撸代码 对zip文件直接进行解析 一条记录对应一行数据 public void readZipCvsFile File file throws Exception 获得输入流 文件为zip格式 zip可以包含对个文件
  • static详解

    一 修饰普通变量 1 局部变量 用法 static 变量类型 变量名 内存中的位置 静态存储区 初始化 未经初始化的局部静态变量会被自动初始化为 0 自动对象的值是任意的 除非他被显示初始化 作用域 作用域仍为局部作用域 当定义它的函数或者
  • APK安装过程及原理详解

    应用程序包的安装是android的特点 APK为AndroidPackage的缩写 Android应用安装有如下四种方式 1 系统应用安装 开机时完成 没有安装界面 2 网络下载应用安装 通过market应用完成 没有安装界面 3 ADB工